├── public └── .gitkeep ├── src ├── lang │ ├── .gitkeep │ ├── en │ │ └── confide.php │ └── pt │ │ └── confide.php ├── views │ ├── .gitkeep │ ├── emails │ │ ├── passwordreset.blade.php │ │ └── confirm.blade.php │ ├── forgot_password.blade.php │ ├── reset_password.blade.php │ ├── generators │ │ ├── routes.blade.php │ │ ├── migration.blade.php │ │ └── controller.blade.php │ ├── login.blade.php │ └── signup.blade.php ├── config │ ├── .gitkeep │ └── config.php ├── migrations │ ├── .gitkeep │ └── 2013_01_13_172956_confide_setup_users_table.php ├── Zizaco │ └── Confide │ │ ├── ConfideFacade.php │ │ ├── ObjectProvider.php │ │ ├── ConfideServiceProvider.php │ │ ├── Confide.php │ │ └── ConfideUser.php └── commands │ ├── MigrationCommand.php │ ├── ControllerCommand.php │ └── RoutesCommand.php ├── tests ├── .gitkeep ├── ConfideUserTest.php └── ConfideTest.php ├── .gitignore ├── .travis.yml ├── phpunit.xml ├── composer.json └── README.md /public/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/lang/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/views/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/config/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/migrations/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.lock 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.3 5 | - 5.4 6 | 7 | before_script: 8 | - curl -s http://getcomposer.org/installer | php 9 | - php composer.phar install --dev 10 | 11 | script: phpunit 12 | -------------------------------------------------------------------------------- /src/Zizaco/Confide/ConfideFacade.php: -------------------------------------------------------------------------------- 1 | {{ Lang::get('confide::confide.email.password_reset.subject') }} 2 | 3 |

{{ Lang::get('confide::confide.email.password_reset.greetings', array( 'name' => $user->username)) }},

4 | 5 |

{{ Lang::get('confide::confide.email.password_reset.body') }}

6 | 7 | {{{ URL::to("user/reset_password/".$token) }}} 8 | 9 | 10 |

{{ Lang::get('confide::confide.email.password_reset.farewell') }}

11 | -------------------------------------------------------------------------------- /src/views/emails/confirm.blade.php: -------------------------------------------------------------------------------- 1 |

{{ Lang::get('confide::confide.email.account_confirmation.subject') }}

2 | 3 |

{{ Lang::get('confide::confide.email.account_confirmation.greetings', array( 'name' => $user->username)) }},

4 | 5 |

{{ Lang::get('confide::confide.email.account_confirmation.body') }}

6 | 7 | {{{ URL::to("user/confirm/{$user->confirmation_code}") }}} 8 | 9 | 10 |

{{ Lang::get('confide::confide.email.account_confirmation.farewell') }}

11 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | ./tests/ 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/migrations/2013_01_13_172956_confide_setup_users_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->string('username'); 19 | $table->string('email'); 20 | $table->string('password'); 21 | $table->string('confirmation_code'); 22 | $table->boolean('confirmed')->default(false); 23 | $table->timestamps(); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | * 30 | * @return void 31 | */ 32 | public function down() 33 | { 34 | Schema::drop('users'); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/views/forgot_password.blade.php: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 |
10 | 11 | @if ( Session::get('error') ) 12 |
{{{ Session::get('error') }}}
13 | @endif 14 | 15 | @if ( Session::get('notice') ) 16 |
{{{ Session::get('notice') }}}
17 | @endif 18 |
19 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zizaco/confide", 3 | "description": "Confide is an authentication solution for Laravel 4", 4 | "keywords": ["laravel","illuminate","auth"], 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Zizaco Zizuini", 9 | "email": "zizaco@gmail.com" 10 | } 11 | ], 12 | "require": { 13 | "php": ">=5.3.0", 14 | "illuminate/support": "4.0.x", 15 | "laravelbook/ardent": "*" 16 | }, 17 | "require-dev": { 18 | "mockery/mockery": "0.7.2", 19 | "illuminate/database": "4.0.x", 20 | "illuminate/auth": "4.0.x" 21 | }, 22 | "suggest": { 23 | "zizaco/entrust":"add Role-based Permissions to Laravel 4" 24 | }, 25 | "autoload": { 26 | "classmap": [ 27 | "src/migrations", 28 | "src/commands" 29 | ], 30 | "psr-0": { 31 | "Zizaco\\Confide": "src/" 32 | } 33 | }, 34 | "minimum-stability": "dev" 35 | } 36 | -------------------------------------------------------------------------------- /src/views/reset_password.blade.php: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | @if ( Session::get('error') ) 11 |
{{{ Session::get('error') }}}
12 | @endif 13 | 14 | @if ( Session::get('notice') ) 15 |
{{{ Session::get('notice') }}}
16 | @endif 17 | 18 |
19 | 20 |
21 |
22 | -------------------------------------------------------------------------------- /src/views/generators/routes.blade.php: -------------------------------------------------------------------------------- 1 | {{{ "\n\n" }}} 2 | @if (! $restful) 3 | 4 | // Confide routes 5 | Route::get( '{{ lcfirst(substr($name,0,-10)) }}/create', '{{ $name }}@create'); 6 | Route::post('{{ lcfirst(substr($name,0,-10)) }}', '{{ $name }}@store'); 7 | Route::get( '{{ lcfirst(substr($name,0,-10)) }}/login', '{{ $name }}@login'); 8 | Route::post('{{ lcfirst(substr($name,0,-10)) }}/login', '{{ $name }}@do_login'); 9 | Route::get( '{{ lcfirst(substr($name,0,-10)) }}/confirm/{code}', '{{ $name }}@confirm'); 10 | Route::get( '{{ lcfirst(substr($name,0,-10)) }}/forgot_password', '{{ $name }}@forgot_password'); 11 | Route::post('{{ lcfirst(substr($name,0,-10)) }}/forgot_password', '{{ $name }}@do_forgot_password'); 12 | Route::get( '{{ lcfirst(substr($name,0,-10)) }}/reset_password/{token}', '{{ $name }}@reset_password'); 13 | Route::post('{{ lcfirst(substr($name,0,-10)) }}/reset_password', '{{ $name }}@do_reset_password'); 14 | Route::get( '{{ lcfirst(substr($name,0,-10)) }}/logout', '{{ $name }}@logout'); 15 | @else 16 | 17 | // Confide RESTful route 18 | Route::controller( 'user', '{{ $name }}'); 19 | @endif 20 | -------------------------------------------------------------------------------- /src/views/generators/migration.blade.php: -------------------------------------------------------------------------------- 1 | {{{ 'increments('id'); 18 | $table->string('username'); 19 | $table->string('email'); 20 | $table->string('password'); 21 | $table->string('confirmation_code'); 22 | $table->boolean('confirmed')->default(false); 23 | $table->timestamps(); 24 | }); 25 | 26 | // Creates password reminders table 27 | Schema::create('password_reminders', function($t) 28 | { 29 | $t->string('email'); 30 | $t->string('token'); 31 | $t->timestamp('created_at'); 32 | }); 33 | } 34 | 35 | /** 36 | * Reverse the migrations. 37 | * 38 | * @return void 39 | */ 40 | public function down() 41 | { 42 | Schema::drop('password_reminders'); 43 | Schema::drop('{{ $table }}'); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/views/login.blade.php: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | 6 | 7 | 13 | 14 | 15 | 19 | 20 | @if ( Session::get('error') ) 21 |
{{{ Session::get('error') }}}
22 | @endif 23 | 24 | @if ( Session::get('notice') ) 25 |
{{{ Session::get('notice') }}}
26 | @endif 27 | 28 | 29 |
30 |
31 | -------------------------------------------------------------------------------- /src/Zizaco/Confide/ConfideServiceProvider.php: -------------------------------------------------------------------------------- 1 | package('zizaco/confide'); 24 | } 25 | 26 | /** 27 | * Register the service provider. 28 | * 29 | * @return void 30 | */ 31 | public function register() 32 | { 33 | $this->registerConfide(); 34 | 35 | $this->registerCommands(); 36 | } 37 | 38 | /** 39 | * Register the application bindings. 40 | * 41 | * @return void 42 | */ 43 | private function registerConfide() 44 | { 45 | $this->app->bind('confide', function($app) 46 | { 47 | return new Confide($app); 48 | }); 49 | } 50 | 51 | /** 52 | * Register the artisan commands. 53 | * 54 | * @return void 55 | */ 56 | private function registerCommands() 57 | { 58 | $this->app['command.confide.controller'] = $this->app->share(function($app) 59 | { 60 | return new ControllerCommand($app); 61 | }); 62 | 63 | $this->app['command.confide.routes'] = $this->app->share(function($app) 64 | { 65 | return new RoutesCommand($app); 66 | }); 67 | 68 | $this->app['command.confide.migration'] = $this->app->share(function($app) 69 | { 70 | return new MigrationCommand($app); 71 | }); 72 | 73 | $this->commands( 74 | 'command.confide.controller', 75 | 'command.confide.routes', 76 | 'command.confide.migration' 77 | ); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/views/signup.blade.php: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | @if ( Session::get('error') ) 17 |
18 | @if ( is_array(Session::get('error')) ) 19 | {{{ head(Session::get('error')) }}} 20 | @endif 21 |
22 | @endif 23 | 24 | @if ( Session::get('notice') ) 25 |
{{{ Session::get('notice') }}}
26 | @endif 27 | 28 |
29 | 30 |
31 | 32 |
33 |
34 | -------------------------------------------------------------------------------- /src/config/config.php: -------------------------------------------------------------------------------- 1 | 9, 16 | 17 | /* 18 | |-------------------------------------------------------------------------- 19 | | Form Views 20 | |-------------------------------------------------------------------------- 21 | | 22 | | The VIEWS used to render forms with Confide methods: 23 | | makeLoginForm, makeSignupForm, makeForgotPasswordForm 24 | | and makeResetPasswordForm. 25 | | 26 | | By default, the out of the box confide views are used 27 | | but you can create your own forms and replace the view 28 | | names here. For example 29 | | 30 | | // To use app/views/user/signup.blade.php: 31 | | 32 | | 'signup_form' => 'user.signup' 33 | | 34 | | 35 | */ 36 | 'login_form' => 'confide::login', 37 | 'signup_form' => 'confide::signup', 38 | 'forgot_password_form' => 'confide::forgot_password', 39 | 'reset_password_form' => 'confide::reset_password', //* 40 | 41 | // * reset_password_form must use $token variable in hidden input field 42 | 43 | /* 44 | |-------------------------------------------------------------------------- 45 | | Email Views 46 | |-------------------------------------------------------------------------- 47 | | 48 | | The VIEWS used to email messages for some Confide events: 49 | | 50 | | By default, the out of the box confide views are used 51 | | but you can create your own forms and replace the view 52 | | names here. For example 53 | | 54 | | // To use app/views/email/confirmation.blade.php: 55 | | 56 | | 'email_account_confirmation' => 'email.confirmation' 57 | | 58 | | 59 | */ 60 | 61 | 'email_reset_password' => 'confide::emails.passwordreset', // with $user and $token. 62 | 'email_account_confirmation' => 'confide::emails.confirm', // with $user 63 | 64 | ); 65 | -------------------------------------------------------------------------------- /src/lang/en/confide.php: -------------------------------------------------------------------------------- 1 | 'Username', 6 | 'password' => 'Password', 7 | 'password_confirmation' => 'Confirm Password', 8 | 'e_mail' => 'Email', 9 | 'username_e_mail' => 'Username or Email', 10 | 11 | 'signup' => array( 12 | 'title' => 'Signup', 13 | 'desc' => 'Signup for new account', 14 | 'confirmation_required' => 'Confirmation required', 15 | 'submit' => 'Create new account', 16 | ), 17 | 18 | 'login' => array( 19 | 'title' => 'Login', 20 | 'desc' => 'Enter your credentials', 21 | 'forgot_password' => '(forgot password)', 22 | 'remember' => 'Remember me', 23 | 'submit' => 'Login', 24 | ), 25 | 26 | 'forgot' => array( 27 | 'title' => 'Forgot password', 28 | 'submit' => 'Continue', 29 | ), 30 | 31 | 'alerts' => array( 32 | 'account_created' => 'Your account has been successfully created. Please check your email for the instructions on how to confirm your account.', 33 | 'too_many_attempts' => 'Too many attempts. Try again in few minutes.', 34 | 'wrong_credentials' => 'Incorrect username, email or password.', 35 | 'not confirmed' => 'Your account may not be confirmed. Check your email for the confirmation link', 36 | 'confirmation' => 'Your account has been confirmed! You may now login.', 37 | 'wrong_confirmation' => 'Wrong confirmation code.', 38 | 'password_forgot' => 'The information regarding password reset was sent to your email.', 39 | 'wrong_password_forgot' => 'User not found.', 40 | 'password_reset' => 'Your password has been changed successfully.', 41 | 'wrong_password_reset' => 'Invalid password. Try again', 42 | ), 43 | 44 | 'email' => array( 45 | 'account_confirmation' => array( 46 | 'subject' => 'Account Confirmation', 47 | 'greetings' => 'Hello :name', 48 | 'body' => 'Please access the link bellow to confirm your account.', 49 | 'farewell' => 'Regards', 50 | ), 51 | 52 | 'password_reset' => array( 53 | 'subject' => 'Password Reset', 54 | 'greetings' => 'Hello :name', 55 | 'body' => 'Access the following link to change your password', 56 | 'farewell' => 'Regards', 57 | ), 58 | ), 59 | 60 | ); 61 | -------------------------------------------------------------------------------- /src/lang/pt/confide.php: -------------------------------------------------------------------------------- 1 | 'Nome de Usuário', 6 | 'password' => 'Senha', 7 | 'password_confirmation' => 'Confirmar senha', 8 | 'e_mail' => 'Email', 9 | 'username_e_mail' => 'Email ou Usuário', 10 | 11 | 'signup' => array( 12 | 'title' => 'Cadastrar', 13 | 'desc' => 'Cadastrar nova conta', 14 | 'confirmation_required' => 'Confirmação necessária', 15 | 'submit' => 'Criar nova conta', 16 | ), 17 | 18 | 'login' => array( 19 | 'title' => 'Entrar', 20 | 'desc' => 'Entre suas credenciais', 21 | 'forgot_password' => '(esqueci minha senha)', 22 | 'remember' => 'Continuar conectado', 23 | 'submit' => 'Entrar', 24 | ), 25 | 26 | 'forgot' => array( 27 | 'title' => 'Esqueci minha senha', 28 | 'submit' => 'Continuar', 29 | ), 30 | 31 | 'alerts' => array( 32 | 'account_created' => 'Sua conta foi criada com sucesso! Por favor verifique em seu e-mail as instruções para confirmar a sua conta.', 33 | 'wrong_credentials' => 'Nome de usuário ou senha incorretos.', 34 | 'too_many_attempts' => 'Muitas tentativas incorretas. Tente novamente mais tarde.', 35 | 'not confirmed' => 'Sua conta pode não estar confirmada. Verifique seu email e procure pelo link de confirmação', 36 | 'confirmation' => 'Sua conta foi confirmada! Você pode entrar agora.', 37 | 'wrong_confirmation' => 'Código de confirmação incorreto.', 38 | 'password_forgot' => 'As informações para a troca de senha foram enviadas ao seu e-mail.', 39 | 'wrong_password_forgot' => 'Usuário não encontrado.', 40 | 'password_reset' => 'Sua senha foi alterada com sucesso.', 41 | 'wrong_password_reset' => 'Senha inválida. Tente novamente.', 42 | ), 43 | 44 | 'email' => array( 45 | 'account_confirmation' => array( 46 | 'subject' => 'Confirmação de conta', 47 | 'greetings' => 'Olá :name', 48 | 'body' => 'Por favor, acesse o link abaixo para confirmar a sua conta', 49 | 'farewell' => 'Att', 50 | ), 51 | 52 | 'password_reset' => array( 53 | 'subject' => 'Troca de senha', 54 | 'greetings' => 'Olá :name', 55 | 'body' => 'Acesse o link a seguir para trocar a sua senha', 56 | 'farewell' => 'Att', 57 | ), 58 | ), 59 | 60 | ); 61 | -------------------------------------------------------------------------------- /src/commands/MigrationCommand.php: -------------------------------------------------------------------------------- 1 | addNamespace('confide',substr(__DIR__,0,-8).'views'); 33 | } 34 | 35 | /** 36 | * Execute the console command. 37 | * 38 | * @return void 39 | */ 40 | public function fire() 41 | { 42 | $table = lcfirst($this->option('table')); 43 | 44 | $this->line(''); 45 | $this->info( "Table name: $table" ); 46 | $message = "An migration that creates the $table table will". 47 | " be created in app/database/migrations directory"; 48 | 49 | $this->comment( $message ); 50 | $this->line(''); 51 | 52 | if ( $this->confirm("Proceed with the migration creation? [Yes|no]") ) 53 | { 54 | $this->line(''); 55 | 56 | $this->info( "Creating migration..." ); 57 | if( $this->createMigration( $table ) ) 58 | { 59 | $this->info( "Migration successfully created!" ); 60 | } 61 | else{ 62 | $this->error( 63 | "Coudn't create migration.\n Check the write permissions". 64 | " within the app/database/migrations directory." 65 | ); 66 | } 67 | 68 | $this->line(''); 69 | 70 | } 71 | } 72 | 73 | /** 74 | * Get the console command options. 75 | * 76 | * @return array 77 | */ 78 | protected function getOptions() 79 | { 80 | $app = app(); 81 | 82 | return array( 83 | array('table', null, InputOption::VALUE_OPTIONAL, 'Table name.', $app['config']->get('auth.table')), 84 | ); 85 | } 86 | 87 | /** 88 | * Create the migration 89 | * 90 | * @param string $name 91 | * @return bool 92 | */ 93 | protected function createMigration( $table = 'users' ) 94 | { 95 | $app = app(); 96 | $migration_file = $this->laravel->path."/database/migrations/".date('Y_m_d_His')."_confide_setup_users_table.php"; 97 | $output = $app['view']->make('confide::generators.migration')->with('table', $table)->render(); 98 | 99 | if( ! file_exists( $migration_file ) ) 100 | { 101 | $fs = fopen($migration_file, 'x'); 102 | if ( $fs ) 103 | { 104 | fwrite($fs, $output); 105 | fclose($fs); 106 | return true; 107 | } 108 | else 109 | { 110 | return false; 111 | } 112 | } 113 | else 114 | { 115 | return false; 116 | } 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/commands/ControllerCommand.php: -------------------------------------------------------------------------------- 1 | addNamespace('confide',substr(__DIR__,0,-8).'views'); 33 | } 34 | 35 | /** 36 | * Execute the console command. 37 | * 38 | * @return void 39 | */ 40 | public function fire() 41 | { 42 | $name = $this->prepareName($this->option('name')); 43 | $restful = $this->option('restful'); 44 | 45 | $this->line(''); 46 | $this->info( "Controller name: $name".(($restful) ? "\nRESTful: Yes" : '') ); 47 | $message = "An authentication ".(($restful) ? 'RESTful ' : '')."controller template with the name $name.php". 48 | " will be created in app/controllers directory and will NOT overwrite any ". 49 | " file."; 50 | 51 | $this->comment( $message ); 52 | $this->line(''); 53 | 54 | if ( $this->confirm("Proceed with the controller creation? [Yes|no]") ) 55 | { 56 | $this->line(''); 57 | 58 | $this->info( "Creating $name..." ); 59 | if( $this->createController( $name, $restful ) ) 60 | { 61 | $this->info( "$name.php Successfully created!" ); 62 | } 63 | else{ 64 | $this->error( 65 | "Coudn't create app/controllers/$name.php.\nCheck the". 66 | " write permissions within the controllers directory". 67 | " or if $name.php already exists. (This command will". 68 | " not overwrite any file. delete the existing $name.php". 69 | " if you wish to continue)." 70 | ); 71 | } 72 | 73 | $this->line(''); 74 | 75 | } 76 | } 77 | 78 | /** 79 | * Get the console command options. 80 | * 81 | * @return array 82 | */ 83 | protected function getOptions() 84 | { 85 | $app = app(); 86 | 87 | return array( 88 | array('name', null, InputOption::VALUE_OPTIONAL, 'Name of the controller.', $app['config']->get('auth.model')), 89 | array('--restful', '-r', InputOption::VALUE_NONE, 'Generate RESTful controller.'), 90 | ); 91 | } 92 | 93 | /** 94 | * Prepare the controller name 95 | * 96 | * @param string $name 97 | * @return string 98 | */ 99 | protected function prepareName($name = '') 100 | { 101 | $name = ( $name != '') ? ucfirst($name) : 'User'; 102 | 103 | if( substr($name,-10) == 'controller' ) 104 | { 105 | $name = substr($name, 0, -10).'Controller'; 106 | } 107 | else 108 | { 109 | $name .= 'Controller'; 110 | } 111 | 112 | return $name; 113 | } 114 | 115 | /** 116 | * Create the controller 117 | * 118 | * @param string $name 119 | * @return bool 120 | */ 121 | protected function createController( $name = '', $restful = false ) 122 | { 123 | $app = app(); 124 | 125 | $controller_file = $this->laravel->path."/controllers/$name.php"; 126 | $output = $app['view']->make('confide::generators.controller') 127 | ->with('name', $name) 128 | ->with('restful', $restful) 129 | ->render(); 130 | 131 | if( ! file_exists( $controller_file ) ) 132 | { 133 | $fs = fopen($controller_file, 'x'); 134 | if ( $fs ) 135 | { 136 | fwrite($fs, $output); 137 | fclose($fs); 138 | return true; 139 | } 140 | else 141 | { 142 | return false; 143 | } 144 | } 145 | else 146 | { 147 | return false; 148 | } 149 | } 150 | 151 | } 152 | -------------------------------------------------------------------------------- /src/commands/RoutesCommand.php: -------------------------------------------------------------------------------- 1 | addNamespace('confide',substr(__DIR__,0,-8).'views'); 33 | } 34 | 35 | /** 36 | * Execute the console command. 37 | * 38 | * @return void 39 | */ 40 | public function fire() 41 | { 42 | $name = $this->prepareName($this->option('controller')); 43 | $restful = $this->option('restful'); 44 | 45 | $this->line(''); 46 | $this->info( "Routes file: app/routes.php" ); 47 | 48 | if(! $restful) 49 | { 50 | $message = "The default Confide routes (to use with the Controller template)". 51 | " will be appended to your routes.php file."; 52 | } 53 | else 54 | { 55 | $message = "A single route to handle every action in a RESTful controller". 56 | " will be appended to your routes.php file. This may be used with a confide". 57 | " controller generated using [-r|--restful] option."; 58 | } 59 | 60 | 61 | $this->comment( $message ); 62 | $this->line(''); 63 | 64 | if ( $this->confirm("Proceed with the append? [Yes|no]") ) 65 | { 66 | $this->line(''); 67 | 68 | $this->info( "Appending routes..." ); 69 | if( $this->appendRoutes( $name, $restful ) ) 70 | { 71 | $this->info( "app/routes.php Patched successfully!" ); 72 | } 73 | else{ 74 | $this->error( 75 | "Coudn't append content to app/routes.php\nCheck the". 76 | " write permissions within the file." 77 | ); 78 | } 79 | 80 | $this->line(''); 81 | 82 | } 83 | } 84 | 85 | /** 86 | * Get the console command options. 87 | * 88 | * @return array 89 | */ 90 | protected function getOptions() 91 | { 92 | $app = app(); 93 | 94 | return array( 95 | array('controller', null, InputOption::VALUE_OPTIONAL, 'Name of the controller.', $app['config']->get('auth.model')), 96 | array('--restful', '-r', InputOption::VALUE_NONE, 'Generate RESTful controller.'), 97 | ); 98 | } 99 | 100 | /** 101 | * Prepare the controller name 102 | * 103 | * @param string $name 104 | * @return string 105 | */ 106 | protected function prepareName( $name = '' ) 107 | { 108 | $name = ( $name != '') ? ucfirst($name) : 'User'; 109 | 110 | if( substr($name,-10) == 'controller' ) 111 | { 112 | $name = substr($name, 0, -10).'Controller'; 113 | } 114 | else 115 | { 116 | $name .= 'Controller'; 117 | } 118 | 119 | return $name; 120 | } 121 | 122 | /** 123 | * Create the controller 124 | * 125 | * @param string $name 126 | * @return bool 127 | */ 128 | protected function appendRoutes( $name = '', $restful = false ) 129 | { 130 | $app = app(); 131 | $routes_file = $this->laravel->path.'/routes.php'; 132 | $confide_routes = $app['view']->make('confide::generators.routes') 133 | ->with('name', $name) 134 | ->with('restful', $restful) 135 | ->render(); 136 | 137 | if( file_exists( $routes_file ) ) 138 | { 139 | $fs = fopen($routes_file, 'a'); 140 | if ( $fs ) 141 | { 142 | fwrite($fs, $confide_routes); 143 | $this->line($confide_routes); 144 | fclose($fs); 145 | return true; 146 | } 147 | else 148 | { 149 | return false; 150 | } 151 | } 152 | else 153 | { 154 | return false; 155 | } 156 | } 157 | 158 | } 159 | -------------------------------------------------------------------------------- /tests/ConfideUserTest.php: -------------------------------------------------------------------------------- 1 | mockApp(); 35 | 36 | $this->confide_user = new ConfideUser; 37 | } 38 | 39 | private function populateUser() 40 | { 41 | $this->confide_user->username = 'uname'; 42 | $this->confide_user->password = '123123'; 43 | $this->confide_user->email = 'mail@sample.com'; 44 | $this->confide_user->confirmation_code = '456456'; 45 | $this->confide_user->confirmed = true; 46 | } 47 | 48 | public function testShouldGetAuthPassword() 49 | { 50 | $this->populateUser(); 51 | 52 | $this->assertEquals( $this->confide_user->password, $this->confide_user->getAuthPassword() ); 53 | } 54 | 55 | public function testShouldConfirm() 56 | { 57 | $this->populateUser(); 58 | 59 | $this->assertNotEquals( 0, $this->confide_user->confirm() ); 60 | 61 | $this->assertEquals( 1, $this->confide_user->confirmed ); 62 | } 63 | 64 | public function testShouldSendForgotPassword() 65 | { 66 | // Should send an email once 67 | ConfideUser::$app['mailer'] = m::mock( 'Mail' ); 68 | ConfideUser::$app['mailer']->shouldReceive('send') 69 | ->andReturn( null ) 70 | ->atLeast(1); 71 | 72 | $this->populateUser(); 73 | 74 | $old_password = $this->confide_user->password; 75 | 76 | $this->assertTrue( $this->confide_user->forgotPassword() ); 77 | } 78 | 79 | public function testShouldChangePassword() 80 | { 81 | $credentials = array( 'email'=>'mail@sample.com', 'password'=>'987987' ); 82 | 83 | $this->populateUser(); 84 | 85 | $old_password = $this->confide_user->password; 86 | 87 | $this->assertTrue( $this->confide_user->resetPassword( $credentials ) ); 88 | 89 | $new_password = $this->confide_user->password; 90 | 91 | // Should have generated a new password code 92 | $this->assertNotEquals( $old_password, $new_password ); 93 | } 94 | 95 | public function testShouldGenerateConfirmationCodeOnSave() 96 | { 97 | // Should send an email once 98 | ConfideUser::$app['mailer'] = m::mock( 'Mail' ); 99 | ConfideUser::$app['mailer']->shouldReceive('send') 100 | ->andReturn( null ) 101 | ->once(); 102 | 103 | $this->populateUser(); 104 | $this->confide_user->confirmation_code = ''; 105 | $this->confide_user->confirmed = false; 106 | 107 | $old_cc = $this->confide_user->confirmation_code; 108 | 109 | $this->assertTrue( $this->confide_user->save() ); 110 | 111 | $new_cc = $this->confide_user->confirmation_code; 112 | 113 | // Should have generated a new confirmation code 114 | $this->assertNotEquals( $old_cc, $new_cc ); 115 | } 116 | 117 | public function testShouldNotGenerateConfirmationCodeIfExists() 118 | { 119 | $this->populateUser(); 120 | 121 | // Considering the model was already saved 122 | $this->confide_user->id = 1; 123 | 124 | $old_cc = $this->confide_user->confirmation_code; 125 | 126 | $this->assertTrue( $this->confide_user->save() ); 127 | 128 | $new_cc = $this->confide_user->confirmation_code; 129 | 130 | // Should not change confirmation code 131 | $this->assertEquals( $old_cc, $new_cc ); 132 | } 133 | 134 | private function mockApp() 135 | { 136 | // Mocks the application components 137 | $app = array(); 138 | 139 | $app['config'] = m::mock( 'Config' ); 140 | $app['config']->shouldReceive( 'get' ) 141 | ->with( 'auth.table' ) 142 | ->andReturn( 'users' ); 143 | 144 | $app['config']->shouldReceive( 'getEnvironment' ) 145 | ->andReturn( 'production' ); 146 | 147 | $app['config']->shouldReceive( 'get' ) 148 | ->with( 'app.key' ) 149 | ->andReturn( '123' ); 150 | 151 | $app['config']->shouldReceive( 'get' ) 152 | ->with( 'confide::throttle_limit' ) 153 | ->andReturn( 9 ); 154 | 155 | $app['config']->shouldReceive( 'get' ) 156 | ->andReturn( 'confide::login' ); 157 | 158 | $app['mailer'] = m::mock( 'Mail' ); 159 | $app['mailer']->shouldReceive('send') 160 | ->andReturn( null ); 161 | 162 | $app['hash'] = m::mock( 'Hash' ); 163 | $app['hash']->shouldReceive('make') 164 | ->andReturn( 'aRandomHash' ); 165 | 166 | $app['db'] = m::mock( 'DatabaseManager' ); 167 | $app['db']->shouldReceive('connection') 168 | ->andReturn( $app['db'] ); 169 | 170 | $app['db']->shouldReceive('table') 171 | ->andReturn( $app['db'] ); 172 | 173 | $app['db']->shouldReceive('insert') 174 | ->andReturn( $app['db'] ); 175 | 176 | $app['db']->shouldReceive('where') 177 | ->andReturn( $app['db'] ); 178 | 179 | $app['db']->shouldReceive('update') 180 | ->andReturn( true ); 181 | 182 | return $app; 183 | } 184 | 185 | } 186 | -------------------------------------------------------------------------------- /src/Zizaco/Confide/Confide.php: -------------------------------------------------------------------------------- 1 | app = app(); 31 | $this->objectRepository = new ObjectProvider; 32 | } 33 | 34 | /** 35 | * Returns the Laravel application 36 | * 37 | * @return Illuminate\Foundation\Application 38 | */ 39 | public function app() 40 | { 41 | return $this->app; 42 | } 43 | 44 | /** 45 | * Returns the model set in auth config 46 | * 47 | * @return string 48 | */ 49 | public function model() 50 | { 51 | $model = $this->app['config']->get('auth.model'); 52 | 53 | return $this->objectRepository->getObject( $model ); 54 | 55 | } 56 | 57 | /** 58 | * Get the currently authenticated user or null. 59 | * 60 | * @return Zizaco\Confide\ConfideUser|null 61 | */ 62 | public function user() 63 | { 64 | return $this->app['auth']->user(); 65 | } 66 | 67 | /** 68 | * Set the user confirmation to true. 69 | * 70 | * @param string $code 71 | * @return bool 72 | */ 73 | public function confirm( $code ) 74 | { 75 | $user = Confide::model()->where('confirmation_code', '=', $code)->get()->first(); 76 | if( $user ) 77 | { 78 | return $user->confirm(); 79 | } 80 | else 81 | { 82 | return false; 83 | } 84 | } 85 | 86 | /** 87 | * Attempt to log a user into the application with 88 | * password and username or email. 89 | * 90 | * @param array $arguments 91 | * @param bool $confirmed_only 92 | * @return void 93 | */ 94 | public function logAttempt( $credentials, $confirmed_only = false ) 95 | { 96 | 97 | if(! $this->reachedThrottleLimit( $credentials ) ) 98 | { 99 | $user = $this->model() 100 | ->where('email','=',$credentials['email']) 101 | ->orWhere('username','=',$credentials['email']) 102 | ->first(); 103 | 104 | if( ! is_null($user) and ($user->confirmed or !$confirmed_only ) and $this->app['hash']->check($credentials['password'], $user->password) ) 105 | { 106 | $remember = isset($credentials['remember']) ? $credentials['remember'] : false; 107 | 108 | $this->app['auth']->login( $user, $remember ); 109 | return true; 110 | } 111 | } 112 | 113 | $this->throttleCount( $credentials ); 114 | 115 | return false; 116 | } 117 | 118 | /** 119 | * Checks if the credentials has been throttled by too 120 | * much failed login attempts 121 | * 122 | * @param array $credentials 123 | * @return mixed Value. 124 | */ 125 | public function isThrottled( $credentials ) 126 | { 127 | // Check how many failed tries have been done 128 | $attempt_key = $this->attemptCacheKey( $credentials ); 129 | $attempts = $this->app['cache']->get($attempt_key, 0); 130 | 131 | if( $attempts >= $this->app['config']->get('confide::throttle_limit') ) 132 | { 133 | return true; 134 | } 135 | else 136 | { 137 | return false; 138 | } 139 | } 140 | 141 | /** 142 | * Send email with information about password reset 143 | * 144 | * @param string $email 145 | * @return bool 146 | */ 147 | public function forgotPassword( $email ) 148 | { 149 | $user = Confide::model()->where('email', '=', $email)->get()->first(); 150 | if( $user ) 151 | { 152 | $user->forgotPassword(); 153 | return true; 154 | } 155 | else 156 | { 157 | return false; 158 | } 159 | } 160 | 161 | /** 162 | * Change user password 163 | * 164 | * @return string 165 | */ 166 | public function resetPassword( $params ) 167 | { 168 | $token = array_get($params, 'token', ''); 169 | 170 | $email = $this->app['db']->connection()->table('password_reminders') 171 | ->select('email')->where('token','=',$token) 172 | ->first(); 173 | 174 | if ($email) 175 | $email = $email->email; 176 | 177 | $user = Confide::model()->where('email', '=', $email)->get()->first(); 178 | if( $user ) 179 | { 180 | return $user->resetPassword( $params ); 181 | } 182 | else 183 | { 184 | return false; 185 | } 186 | } 187 | 188 | /** 189 | * Log the user out of the application. 190 | * 191 | * @return void 192 | */ 193 | public function logout() 194 | { 195 | $this->app['auth']->logout(); 196 | } 197 | 198 | /** 199 | * Display the default login view 200 | * 201 | * @return Illuminate\View\View 202 | */ 203 | public function makeLoginForm() 204 | { 205 | return $this->app['view']->make($this->app['config']->get('confide::login_form')); 206 | } 207 | 208 | /** 209 | * Display the default signup view 210 | * 211 | * @return Illuminate\View\View 212 | */ 213 | public function makeSignupForm() 214 | { 215 | return $this->app['view']->make( $this->app['config']->get('confide::signup_form') ); 216 | } 217 | 218 | /** 219 | * Display the forget password view 220 | * 221 | * @return Illuminate\View\View 222 | */ 223 | public function makeForgotPasswordForm() 224 | { 225 | return $this->app['view']->make( $this->app['config']->get('confide::forgot_password_form') ); 226 | } 227 | 228 | /** 229 | * Display the forget password view 230 | * 231 | * @return Illuminate\View\View 232 | */ 233 | public function makeResetPasswordForm( $token ) 234 | { 235 | return $this->app['view']->make( $this->app['config']->get('confide::reset_password_form') , array('token'=>$token)); 236 | } 237 | 238 | /** 239 | * Returns the name of the cache key that will be used 240 | * to store the failed attempts 241 | * 242 | * @param array $credentials. 243 | * @return string. 244 | */ 245 | protected function attemptCacheKey( $credentials ) 246 | { 247 | return 'confide_flogin_attempt_' 248 | .$this->app['request']->server('REMOTE_ADDR') 249 | .$this->app['request']->server('HTTP_X_FORWARDED_FOR') 250 | .$credentials['email']; 251 | } 252 | 253 | /** 254 | * Checks if the current IP / email has reached the throttle 255 | * limit 256 | * 257 | * @param array $credentials 258 | * @return bool Value. 259 | */ 260 | protected function reachedThrottleLimit( $credentials ) 261 | { 262 | $attempt_key = $this->attemptCacheKey( $credentials ); 263 | $attempts = $this->app['cache']->get($attempt_key, 0); 264 | 265 | return $attempts >= $this->app['config']->get('confide::throttle_limit'); 266 | } 267 | 268 | /** 269 | * Increment IP / email throttle count 270 | * 271 | * @param array $credentials 272 | * @return void 273 | */ 274 | protected function throttleCount( $credentials ) 275 | { 276 | $attempt_key = $this->attemptCacheKey( $credentials ); 277 | $attempts = $this->app['cache']->get($attempt_key, 0); 278 | 279 | $this->app['cache']->put($attempt_key, $attempts+1, 2); // used throttling login attempts 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /src/Zizaco/Confide/ConfideUser.php: -------------------------------------------------------------------------------- 1 | 'required|alpha_dash|between:4,16', 51 | 'email' => 'required|email', 52 | 'password' => 'required|between:4,11|confirmed', 53 | ); 54 | 55 | /** 56 | * Create a new ConfideUser instance. 57 | */ 58 | public function __construct() 59 | { 60 | parent::__construct(); 61 | 62 | if ( ! static::$app ) 63 | static::$app = app(); 64 | 65 | $this->table = static::$app['config']->get('auth.table'); 66 | } 67 | 68 | /** 69 | * Get the unique identifier for the user. 70 | * 71 | * @return mixed 72 | */ 73 | public function getAuthIdentifier() 74 | { 75 | return $this->getKey(); 76 | } 77 | 78 | /** 79 | * Get the password for the user. 80 | * 81 | * @return string 82 | */ 83 | public function getAuthPassword() 84 | { 85 | return $this->password; 86 | } 87 | 88 | /** 89 | * Confirm the user (usually means that the user) 90 | * email is valid. 91 | * 92 | * @return bool 93 | */ 94 | public function confirm() 95 | { 96 | $this->confirmed = 1; 97 | 98 | // Executes directly using query builder 99 | return static::$app['db']->table($this->table) 100 | ->where($this->getKeyName(), $this->getKey()) 101 | ->update(array('confirmed'=>1)); 102 | } 103 | 104 | /** 105 | * Send email with information about password reset 106 | * 107 | * @return string 108 | */ 109 | public function forgotPassword() 110 | { 111 | $token = substr(md5(microtime().static::$app['config']->get('app.key')),-16); 112 | 113 | static::$app['db']->connection()->table('password_reminders')->insert(array( 114 | 'email'=> $this->email, 115 | 'token'=> $token, 116 | 'created_at'=> new \DateTime 117 | )); 118 | 119 | $view = static::$app['config']->get('confide::email_reset_password'); 120 | 121 | $this->sendEmail( 'confide::confide.email.password_reset.subject', $view, array('user'=>$this, 'token'=>$token) ); 122 | 123 | return true; 124 | } 125 | 126 | /** 127 | * Change user password 128 | * 129 | * @return string 130 | */ 131 | public function resetPassword( $params ) 132 | { 133 | $this->password = array_get($params, 'password', ''); 134 | $this->password_confirmation = array_get($params, 'password_confirmation', ''); 135 | 136 | if ( $this->save() ) 137 | { 138 | return true; 139 | } 140 | else{ 141 | return false; 142 | } 143 | } 144 | 145 | /** 146 | * Overwrite the Ardent save method. Saves model into 147 | * database 148 | * 149 | * @param array $rules:array 150 | * @param array $customMessages 151 | * @param closure $beforeSave 152 | * @param callable $afterSave 153 | * @return bool 154 | */ 155 | public function save( $rules = array(), $customMessages = array(), Closure $beforeSave = null, Closure $afterSave = null ) 156 | { 157 | return $this->real_save( $rules, $customMessages, $beforeSave, $afterSave ); 158 | } 159 | 160 | /** 161 | * Ardent method overloading: 162 | * Before save the user. Generate a confirmation 163 | * code if is a new user. 164 | * 165 | * @param bool $forced Indicates whether the user is being saved forcefully 166 | * @return bool 167 | */ 168 | public function beforeSave( $forced = false ) 169 | { 170 | if ( empty($this->id) ) 171 | { 172 | $this->confirmation_code = md5(microtime().static::$app['config']->get('app.key')); 173 | } 174 | 175 | /* 176 | * Remove password_confirmation field before save to 177 | * database. 178 | */ 179 | if ( isset($this->password_confirmation) ) 180 | { 181 | unset( $this->password_confirmation ); 182 | } 183 | 184 | return true; 185 | } 186 | 187 | /** 188 | * Ardent method overloading: 189 | * After save, delivers the confirmation link email. 190 | * code if is a new user. 191 | * 192 | * @param bool $forced Indicates whether the user is being saved forcefully 193 | * @return bool 194 | */ 195 | public function afterSave( $success, $forced = false ) 196 | { 197 | if ( $success and ! $this->confirmed ) 198 | { 199 | $view = static::$app['config']->get('confide::email_account_confirmation'); 200 | 201 | $this->sendEmail( 'confide::confide.email.account_confirmation.subject', $view, array('user' => $this) ); 202 | } 203 | 204 | return true; 205 | } 206 | 207 | /** 208 | * Runs the real eloquent save method or returns 209 | * true if it's under testing. Because Eloquent 210 | * and Ardent save methods are not Confide's 211 | * responsibility. 212 | * 213 | * @return bool 214 | */ 215 | protected function real_save( $rules = array(), $customMessages = array(), Closure $beforeSave = null, Closure $afterSave = null ) 216 | { 217 | if ( defined('CONFIDE_TEST') ) 218 | { 219 | $this->beforeSave(); 220 | $this->afterSave( true ); 221 | return true; 222 | } 223 | else{ 224 | 225 | /* 226 | * This will make sure that a non modified password 227 | * will not trigger validation error. 228 | */ 229 | if( empty($rules) && $this->password == $this->getOriginal('password') ) 230 | { 231 | $rules = static::$rules; 232 | $rules['password'] = 'required'; 233 | } 234 | 235 | return parent::save( $rules, $customMessages, $beforeSave, $afterSave ); 236 | } 237 | } 238 | 239 | /** 240 | * Add the namespace 'confide::' to view hints. 241 | * this makes possible to send emails using package views from 242 | * the command line. 243 | * 244 | * @return void 245 | */ 246 | protected static function fixViewHint() 247 | { 248 | if (isset(static::$app['view.finder'])) 249 | static::$app['view.finder']->addNamespace('confide', __DIR__.'/../../views'); 250 | } 251 | 252 | /** 253 | * Send email using the lang sentence as subject and the viewname 254 | * 255 | * @param mixed $subject_translation 256 | * @param mixed $view_name 257 | * @return voi. 258 | */ 259 | protected function sendEmail( $subject_translation, $view_name, $params = array() ) 260 | { 261 | if ( static::$app['config']->getEnvironment() == 'testing' ) 262 | return; 263 | 264 | static::fixViewHint(); 265 | 266 | $user = $this; 267 | 268 | static::$app['mailer']->send($view_name, $params, function($m) use ($subject_translation, $user) 269 | { 270 | $m->to( $user->email ) 271 | ->subject( ConfideUser::$app['translator']->get($subject_translation) ); 272 | }); 273 | } 274 | } 275 | -------------------------------------------------------------------------------- /src/views/generators/controller.blade.php: -------------------------------------------------------------------------------- 1 | {{{ 'username = Input::get( 'username' ); 33 | ${{ lcfirst(Config::get('auth.model')) }}->email = Input::get( 'email' ); 34 | ${{ lcfirst(Config::get('auth.model')) }}->password = Input::get( 'password' ); 35 | 36 | // The password confirmation will be removed from model 37 | // before saving. This field will be used in Ardent's 38 | // auto validation. 39 | ${{ lcfirst(Config::get('auth.model')) }}->password_confirmation = Input::get( 'password_confirmation' ); 40 | 41 | // Save if valid. Password field will be hashed before save 42 | ${{ lcfirst(Config::get('auth.model')) }}->save(); 43 | 44 | if ( ${{ lcfirst(Config::get('auth.model')) }}->id ) 45 | { 46 | // Redirect with success message, You may replace "Lang::get(..." for your custom message. 47 | @if (! $restful) 48 | return Redirect::action('{{ $name }}@login') 49 | @else 50 | return Redirect::to('user/login') 51 | @endif 52 | ->with( 'notice', Lang::get('confide::confide.alerts.account_created') ); 53 | } 54 | else 55 | { 56 | // Get validation errors (see Ardent package) 57 | $error = ${{ lcfirst(Config::get('auth.model')) }}->getErrors()->all(); 58 | 59 | @if (! $restful) 60 | return Redirect::action('{{ $name }}@create') 61 | @else 62 | return Redirect::to('user/create') 63 | @endif 64 | ->withInput(Input::except('password')) 65 | ->with( 'error', $error ); 66 | } 67 | } 68 | 69 | /** 70 | * Displays the login form 71 | * 72 | */ 73 | public function {{ (! $restful) ? 'login' : 'getLogin' }}() 74 | { 75 | if( Confide::user() ) 76 | { 77 | // If user is logged, redirect to internal 78 | // page, change it to '/admin', '/dashboard' or something 79 | return Redirect::to('/'); 80 | } 81 | else 82 | { 83 | return Confide::makeLoginForm(); 84 | } 85 | } 86 | 87 | /** 88 | * Attempt to do login 89 | * 90 | */ 91 | public function {{ (! $restful) ? 'do_login' : 'postLogin' }}() 92 | { 93 | $input = array( 94 | 'email' => Input::get( 'email' ), // May be the username too 95 | 'password' => Input::get( 'password' ), 96 | 'remamber' => Input::get( 'remember' ), 97 | ); 98 | 99 | // If you wish to only allow login from confirmed users, call logAttempt 100 | // with the second parameter as true. 101 | // logAttempt will check if the 'email' perhaps is the username. 102 | if ( Confide::logAttempt( $input ) ) 103 | { 104 | // If the session 'loginRedirect' is set, then redirect 105 | // to that route. Otherwise redirect to '/' 106 | $r = Session::get('loginRedirect'); 107 | if (!empty($r)) 108 | { 109 | Session::forget('loginRedirect'); 110 | return Redirect::to($r); 111 | } 112 | 113 | return Redirect::to('/'); // change it to '/admin', '/dashboard' or something 114 | } 115 | else 116 | { 117 | // Check if there was too many login attempts 118 | if( Confide::isThrottled( $input ) ) 119 | { 120 | $err_msg = Lang::get('confide::confide.alerts.too_many_attempts'); 121 | } 122 | else 123 | { 124 | $err_msg = Lang::get('confide::confide.alerts.wrong_credentials'); 125 | } 126 | 127 | @if (! $restful) 128 | return Redirect::action('{{ $name }}@login') 129 | @else 130 | return Redirect::to('user/login') 131 | @endif 132 | ->withInput(Input::except('password')) 133 | ->with( 'error', $err_msg ); 134 | } 135 | } 136 | 137 | /** 138 | * Attempt to confirm account with code 139 | * 140 | * @param string $code 141 | */ 142 | public function {{ (! $restful) ? 'confirm' : 'getConfirm' }}( $code ) 143 | { 144 | if ( Confide::confirm( $code ) ) 145 | { 146 | $notice_msg = Lang::get('confide::confide.alerts.confirmation'); 147 | @if (! $restful) 148 | return Redirect::action('{{ $name }}@login') 149 | @else 150 | return Redirect::to('user/login') 151 | @endif 152 | ->with( 'notice', $notice_msg ); 153 | } 154 | else 155 | { 156 | $error_msg = Lang::get('confide::confide.alerts.wrong_confirmation'); 157 | @if (! $restful) 158 | return Redirect::action('{{ $name }}@login') 159 | @else 160 | return Redirect::to('user/login') 161 | @endif 162 | ->with( 'error', $error_msg ); 163 | } 164 | } 165 | 166 | /** 167 | * Displays the forgot password form 168 | * 169 | */ 170 | public function {{ (! $restful) ? 'forgot_password' : 'getForgot' }}() 171 | { 172 | return Confide::makeForgotPasswordForm(); 173 | } 174 | 175 | /** 176 | * Attempt to send change password link to the given email 177 | * 178 | */ 179 | public function {{ (! $restful) ? 'do_forgot_password' : 'postForgot' }}() 180 | { 181 | if( Confide::forgotPassword( Input::get( 'email' ) ) ) 182 | { 183 | $notice_msg = Lang::get('confide::confide.alerts.password_forgot'); 184 | @if (! $restful) 185 | return Redirect::action('{{ $name }}@login') 186 | @else 187 | return Redirect::to('user/login') 188 | @endif 189 | ->with( 'notice', $notice_msg ); 190 | } 191 | else 192 | { 193 | $error_msg = Lang::get('confide::confide.alerts.wrong_password_forgot'); 194 | @if (! $restful) 195 | return Redirect::action('{{ $name }}@forgot_password') 196 | @else 197 | return Redirect::to('user/forgot') 198 | @endif 199 | ->withInput() 200 | ->with( 'error', $error_msg ); 201 | } 202 | } 203 | 204 | /** 205 | * Shows the change password form with the given token 206 | * 207 | */ 208 | public function {{ (! $restful) ? 'reset_password' : 'getReset' }}( $token ) 209 | { 210 | return Confide::makeResetPasswordForm( $token ); 211 | } 212 | 213 | /** 214 | * Attempt change password of the user 215 | * 216 | */ 217 | public function {{ (! $restful) ? 'do_reset_password' : 'postReset' }}() 218 | { 219 | $input = array( 220 | 'token'=>Input::get( 'token' ), 221 | 'password'=>Input::get( 'password' ), 222 | 'password_confirmation'=>Input::get( 'password_confirmation' ), 223 | ); 224 | 225 | // By passing an array with the token, password and confirmation 226 | if( Confide::resetPassword( $input ) ) 227 | { 228 | $notice_msg = Lang::get('confide::confide.alerts.password_reset'); 229 | @if (! $restful) 230 | return Redirect::action('{{ $name }}@login') 231 | @else 232 | return Redirect::to('user/login') 233 | @endif 234 | ->with( 'notice', $notice_msg ); 235 | } 236 | else 237 | { 238 | $error_msg = Lang::get('confide::confide.alerts.wrong_password_reset'); 239 | @if (! $restful) 240 | return Redirect::action('{{ $name }}@reset_password', array('token'=>$input['token'])) 241 | @else 242 | return Redirect::to('user/reset') 243 | @endif 244 | ->withInput() 245 | ->with( 'error', $error_msg ); 246 | } 247 | } 248 | 249 | /** 250 | * Log the user out of the application. 251 | * 252 | */ 253 | public function {{ (! $restful) ? 'logout' : 'getLogout' }}() 254 | { 255 | Confide::logout(); 256 | 257 | return Redirect::to('/'); 258 | } 259 | 260 | } 261 | -------------------------------------------------------------------------------- /tests/ConfideTest.php: -------------------------------------------------------------------------------- 1 | mockApp(); 23 | $this->confide = new Confide(); 24 | 25 | // Set the app attribute with mock 26 | $this->confide->app = $app; 27 | } 28 | 29 | public function testGetModel() 30 | { 31 | // Make shure it grabbed the model from config 32 | $config = m::mock('Illuminate\Config\Repository'); 33 | $config->shouldReceive('get') 34 | ->with('auth.model') 35 | ->andReturn( 'User' ) 36 | ->once(); 37 | $this->confide->app['config'] = $config; 38 | 39 | // Mocks an user 40 | $confide_user = $this->mockConfideUser(); 41 | 42 | // Make shure the object provider returns the 43 | // user object when called 44 | $this->objProviderShouldReturn( 'User', $confide_user ); 45 | 46 | $user = $this->confide->model(); 47 | 48 | $this->assertNotNull( $user ); 49 | } 50 | 51 | public function testShouldGetUser() 52 | { 53 | $confide_user = $this->mockConfideUser(); 54 | 55 | // Laravel auth component should return user 56 | $auth = m::mock('Illuminate\Auth\Guard'); 57 | $auth->shouldReceive('user') 58 | ->andReturn( $confide_user ) 59 | ->once(); 60 | $this->confide->app['auth'] = $auth; 61 | 62 | $this->assertEquals( $confide_user, $this->confide->user() ); 63 | } 64 | 65 | public function testShouldConfirm() 66 | { 67 | $confide_user = $this->mockConfideUser(); 68 | $confide_user->shouldReceive('confirm') 69 | ->andReturn( true ) 70 | ->once(); 71 | 72 | $this->objProviderShouldReturn( 'User', $confide_user ); 73 | 74 | $this->assertTrue( $this->confide->confirm( '123123' ) ); 75 | } 76 | 77 | public function testShouldLogAttempt() 78 | { 79 | $confide_user = $this->mockConfideUser(); 80 | 81 | // Considering a valid hash check from hash component 82 | $hash = m::mock('Illuminate\Hashing\HasherInterface'); 83 | $hash->shouldReceive('check') 84 | ->andReturn( true ) 85 | ->times(2); // 2 successfull logins 86 | $this->confide->app['hash'] = $hash; 87 | 88 | $this->objProviderShouldReturn( 'User', $confide_user ); 89 | 90 | $this->assertTrue( 91 | $this->confide->logAttempt( array( 'email'=>'username', 'password'=>'123123' ) ) 92 | ); 93 | 94 | // Should not login with unconfirmed user. 95 | $this->assertFalse( 96 | $this->confide->logAttempt( array( 'email'=>'username', 'password'=>'123123' ), true ) 97 | ); 98 | 99 | $confide_user->confirmed = 1; 100 | 101 | // Should login because now the user is confirmed 102 | $this->assertTrue( 103 | $this->confide->logAttempt( array( 'email'=>'username', 'password'=>'123123' ), true ) 104 | ); 105 | } 106 | 107 | public function testShouldThrottleLogAttempt() 108 | { 109 | $tries = 15; 110 | 111 | $confide_user = $this->mockConfideUser(); 112 | $confide_user->shouldReceive('get','first') 113 | ->andReturn( null ); 114 | 115 | $this->objProviderShouldReturn( 'User', $confide_user ); 116 | 117 | $this->confide->app['hash']->shouldReceive('check') 118 | ->andReturn( false ); 119 | 120 | for ($i=0; $i < $tries; $i++) { 121 | 122 | // Simulates cache values 123 | $this->useCacheForThrottling($i); 124 | 125 | // Make shure the login is not happening anyway 126 | $this->assertFalse( 127 | $this->confide->logAttempt( array('email'=>'wrong', 'password'=>'wrong') ) 128 | ); 129 | } 130 | 131 | // Check if the credentials has been throttled 132 | $this->assertTrue( 133 | $this->confide->isThrottled( array('email'=>'wrong', 'password'=>'wrong') ) 134 | ); 135 | } 136 | 137 | public function testShouldResetPassword() 138 | { 139 | $confide_user = $this->mockConfideUser(); 140 | $confide_user->shouldReceive('resetPassword') 141 | ->andReturn( true ) 142 | ->once(); 143 | 144 | $this->objProviderShouldReturn( 'User', $confide_user ); 145 | 146 | $this->assertTrue( $this->confide->resetPassword( 'mail@sample.com' ) ); 147 | } 148 | 149 | public function testShouldLogout() 150 | { 151 | // Make shure auth logout method is called 152 | $auth = m::mock('Illuminate\Auth\Guard'); 153 | $auth->shouldReceive('logout') 154 | ->once(); 155 | 156 | $this->confide->app['auth'] = $auth; 157 | $this->assertEquals( null, $this->confide->logout() ); 158 | } 159 | 160 | public function testShouldMakeForms() 161 | { 162 | // Make shure view make method is called 3 times 163 | $view = m::mock('Illuminate\View\Environment\View'); 164 | $view->shouldReceive('make') 165 | ->andReturn( 'Content' ) 166 | ->times( 3 ); 167 | 168 | $this->confide->app['view'] = $view; 169 | 170 | $this->assertNotEquals( null, $this->confide->MakeLoginForm() ); 171 | $this->assertNotEquals( null, $this->confide->makeSignupForm() ); 172 | $this->assertNotEquals( null, $this->confide->makeForgotPasswordForm() ); 173 | } 174 | 175 | private function mockConfideUser() 176 | { 177 | $confide_user = m::mock( 'Illuminate\Auth\UserInterface' ); 178 | $confide_user->username = 'uname'; 179 | $confide_user->password = '123123'; 180 | $confide_user->confirmed = 0; 181 | $confide_user->shouldReceive('where','get', 'orWhere','first', 'all') 182 | ->andReturn( $confide_user ); 183 | 184 | return $confide_user; 185 | } 186 | 187 | private function mockApp() 188 | { 189 | // Mocks the application components that 190 | // are not Confide's responsibility 191 | $app = array(); 192 | 193 | $app['config'] = m::mock( 'Config' ); 194 | $app['config']->shouldReceive( 'get' ) 195 | ->with( 'auth.table' ) 196 | ->andReturn( 'users' ); 197 | 198 | $app['config']->shouldReceive( 'get' ) 199 | ->with( 'auth.model' ) 200 | ->andReturn( 'User' ); 201 | 202 | $app['config']->shouldReceive( 'get' ) 203 | ->with( 'app.key' ) 204 | ->andReturn( '123' ); 205 | 206 | $app['config']->shouldReceive( 'get' ) 207 | ->with( 'confide::throttle_limit' ) 208 | ->andReturn( 9 ); 209 | 210 | $app['config']->shouldReceive( 'get' ) 211 | ->andReturn( 'confide::login' ); 212 | 213 | $app['mail'] = m::mock( 'Mail' ); 214 | $app['mail']->shouldReceive('send') 215 | ->andReturn( null ); 216 | 217 | $app['hash'] = m::mock( 'Hash' ); 218 | $app['hash']->shouldReceive('make') 219 | ->andReturn( 'aRandomHash' ); 220 | 221 | $app['cache'] = m::mock( 'Cache' ); 222 | $app['cache']->shouldReceive('get') 223 | ->andReturn( 0 ); 224 | $app['cache']->shouldReceive('put'); 225 | 226 | $app['auth'] = m::mock( 'Auth' ); 227 | $app['auth']->shouldReceive('login') 228 | ->andReturn( true ); 229 | 230 | $app['request'] = m::mock( 'Request' ); 231 | $app['request']->shouldReceive('server') 232 | ->andReturn( null ); 233 | 234 | $app['db'] = m::mock( 'DatabaseManager' ); 235 | $app['db']->shouldReceive('connection') 236 | ->andReturn( $app['db'] ); 237 | $app['db']->shouldReceive('table') 238 | ->andReturn( $app['db'] ); 239 | $app['db']->shouldReceive('select') 240 | ->andReturn( $app['db'] ); 241 | $app['db']->shouldReceive('where') 242 | ->andReturn( $app['db'] ); 243 | $app['db']->shouldReceive('first') 244 | ->andReturn( $app['db'] ); 245 | $app['db']->email = 'test@example.com'; 246 | 247 | return $app; 248 | } 249 | 250 | private function useCacheForThrottling( $value ) 251 | { 252 | $cache = m::mock('Illuminate\Cache\Store'); 253 | $cache->shouldReceive('put') 254 | ->with( "confide_flogin_attempt_wrong", $value+1, 2 ) 255 | ->once(); 256 | $cache->shouldReceive('get') 257 | ->andReturn( $value ); 258 | $this->confide->app['cache'] = $cache; 259 | } 260 | 261 | /** 262 | * the ObjectProvider getObject method should 263 | * be called with $class to return $object. 264 | * 265 | * @param string $class 266 | * @param mixed $obj 267 | * @return void 268 | */ 269 | private function objProviderShouldReturn( $class, $obj ) 270 | { 271 | $obj_provider = m::mock('ObjectProvider'); 272 | $obj_provider->shouldReceive('getObject') 273 | ->with($class) 274 | ->andReturn( $obj ); 275 | 276 | $this->confide->objectRepository = $obj_provider; 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Confide (Laravel4 Package) 2 | 3 | ![Confide Poster](https://dl.dropbox.com/u/12506137/libs_bundles/confide.png) 4 | 5 | [![Build Status](https://api.travis-ci.org/Zizaco/confide.png)](https://travis-ci.org/Zizaco/confide) 6 | [![ProjectStatus](http://stillmaintained.com/Zizaco/confide.png)](http://stillmaintained.com/Zizaco/confide) 7 | 8 | Confide is a authentication solution for **Laravel4** made to eliminate repetitive tasks involving the management of users: Account creation, login, logout, confirmation by e-mail, password reset, etc. 9 | 10 | Confide aims to be simple to use, quick to configure and flexible. 11 | 12 | ## Features 13 | 14 | **Current:** 15 | - Account confirmation (through confirmation link). 16 | - Password reset (sending email with a change password link). 17 | - Easily render forms for login, signup and password reset. 18 | - Generate customizable routes for login, signup, password reset, confirmation, etc. 19 | - Generate a customizable controller that handles the basic user account actions. 20 | - Contains a set of methods to help basic user features. 21 | - Integrated with the Laravel Auth component/configs. 22 | - Field/model validation (Powered by [Ardent](http://laravelbook.github.com/ardent "Ardent")). 23 | - Login throttling. 24 | - Redirecting to previous route after authentication. 25 | 26 | If you are looking for user roles and permissions see [Entrust](https://github.com/Zizaco/entrust) 27 | 28 | **Planned:** 29 | - Captcha in user signup and password reset. 30 | - General improvements. 31 | 32 | ## Quick start 33 | 34 | ### Required setup 35 | 36 | In the `require` key of `composer.json` file add the following 37 | 38 | "zizaco/confide": "dev-master" 39 | 40 | Run the Composer update comand 41 | 42 | $ composer update 43 | 44 | In your `config/app.php` add `'Zizaco\Confide\ConfideServiceProvider'` to the end of the `$providers` array 45 | 46 | 'providers' => array( 47 | 48 | 'Illuminate\Foundation\Providers\ArtisanServiceProvider', 49 | 'Illuminate\Auth\AuthServiceProvider', 50 | ... 51 | 'Zizaco\Confide\ConfideServiceProvider', 52 | 53 | ), 54 | 55 | At the end of `config/app.php` add `'Confide' => 'Zizaco\Confide\ConfideFacade'` to the `$aliases` array 56 | 57 | 'aliases' => array( 58 | 59 | 'App' => 'Illuminate\Support\Facades\App', 60 | 'Artisan' => 'Illuminate\Support\Facades\Artisan', 61 | ... 62 | 'Confide' => 'Zizaco\Confide\ConfideFacade', 63 | 64 | ), 65 | 66 | ### Configuration 67 | 68 | Set the properly values to the `config/auth.php`. This values will be used by confide to generate the database migration and to generate controllers and routes. 69 | 70 | Set the `address` and `name` from the `from` array in `config/mail.php`. Those will be used to send account confirmation and password reset emails to the users. 71 | 72 | ### User model 73 | 74 | Now generate the Confide migration and the reminder password table migration: 75 | 76 | $ php artisan confide:migration 77 | 78 | It will generate the `_confide_setup_users_table.php` migration. You may now run it with the artisan migrate command: 79 | 80 | $ php artisan migrate 81 | 82 | It will setup a table containing `username`, `email`, `password`, `confirmation_code` and `confirmed` fields, which are the default fields needed for Confide use. Feel free to add more fields to the database. 83 | 84 | Change your User model in `app/models/User.php` to: 85 | 86 | render() }}`. 126 | 2. Generate a controller with the template contained in Confide throught the artisan command `$ php artisan confide:controller`. If a controller with the same name exists it will **NOT** be overwritten. 127 | 3. Generate routes matching the controller template throught the artisan command `$ php artisan confide:routes`. Your `routes.php` will **NOT** be overwritten. 128 | 129 | ### Advanced 130 | 131 | #### Using custom table / model name 132 | 133 | You can change the model name that will be authenticated in the `config/auth.php` file. 134 | Confide uses the values present in that configuration file. 135 | 136 | To change the controller name when dumping the default controller template you can use the --name option. 137 | 138 | $ php artisan confide:controller --name Employee 139 | 140 | Will result in `EmployeeController` 141 | 142 | Then, when dumping the routes, you should use the --controller option to match the existing controller. 143 | 144 | $ php artisan confide:routes --controller Employee 145 | 146 | #### Using custom form or emails 147 | 148 | First, publish the config files: 149 | 150 | $ php artisan config:publish zizaco/confide 151 | 152 | Then edit the view names in `app/config/packages/zizaco/confide/config.php`. 153 | 154 | #### Validate model fields 155 | 156 | To change the validation rules of the User model you can take a look at [Ardent](http://laravelbook.github.com/ardent/#validation "Ardent Validation Rulez"). For example: 157 | 158 | 'required|alpha_dash|between:6,12', 169 | 'email' => 'required|email', 170 | 'password' => 'required|between:4,11|confirmed', 171 | ); 172 | 173 | } 174 | 175 | Feel free to add more fields to your table and to the validation array. Then you should build you own signup form with the aditional fields. 176 | 177 | #### RESTful controller 178 | 179 | If you want to generate a [RESTful controller](https://github.com/laravel/docs/blob/master/controllers.md#restful-controllers) you can use the aditional `--restful` or `-r` option. 180 | 181 | $ php artisan confide:controller --restful 182 | 183 | Will result in a [RESTful controller](https://github.com/laravel/docs/blob/master/controllers.md#restful-controllers) 184 | 185 | Then, when dumping the routes, you should use the --restful option to match the existing controller. 186 | 187 | $ php artisan confide:routes --restful 188 | 189 | #### User roles and permissions 190 | 191 | In order not to bloat Confide with not related features, the role and permission was developed as another package: [Entrust](https://github.com/Zizaco/entrust). This package couples very well with Confide. 192 | 193 | See [Entrust](https://github.com/Zizaco/entrust) 194 | 195 | #### Redirecting to previous route after login 196 | 197 | When defining your filter you should set the `'loginRedirect'` session variable. For example: 198 | 199 | // filters.php 200 | 201 | Route::filter('auth', function() 202 | { 203 | if ( Auth::guest() ) // If the user is not logged in 204 | { 205 | // Set the loginRedirect session variable 206 | Session::put( 'loginRedirect', Request::url() ); 207 | 208 | // Redirect back to user login 209 | return Redirect::to( 'user/login' ); 210 | } 211 | }); 212 | 213 | // Only authenticated users will be able to access routes that begins with 214 | // 'admin'. Ex: 'admin/posts', 'admin/categories'. 215 | Route::when('admin*', 'auth'); 216 | 217 | or, if you are using [Entrust](https://github.com/Zizaco/entrust) ;) 218 | 219 | // filters.php 220 | 221 | Entrust::routeNeedsRole( 'admin*', 'Admin', function(){ 222 | Session::put( 'loginRedirect', Request::url() ); 223 | return Redirect::to( 'user/login' ); 224 | } ); 225 | 226 | ## Troubleshooting 227 | 228 | __[Exception] SQLSTATE[HY000]: General error: 1364 Field 'confirmation_code' doesn't have a default value...__ 229 | 230 | If you overwrite the `beforeSave()` method in your model, make sure to call `parent::beforeSave()`: 231 | 232 | public function beforeSave( $forced = false ){ 233 | 234 | parent::beforeSave( $forced) // Don't forget this 235 | 236 | // Your stuff 237 | } 238 | 239 | __Confirmation link is not sent when user signup__ 240 | 241 | Same as above. If you overwrite the `afterSave()` method in your model, make sure to call `parent::afterSave()`: 242 | 243 | __Users are able to login without confirming account__ 244 | 245 | If you want only confirmed users to login, in your `UserController`, instead of simply calling `logAttempt( $input )`, call `logAttempt( $input, true )`. The second parameter stands for _"confirmed_only"_. 246 | 247 | 248 | ## License 249 | 250 | Confide is free software distributed under the terms of the MIT license 251 | 252 | ## Aditional information 253 | 254 | Any questions, feel free to contact me or ask [here](http://forums.laravel.io/viewtopic.php?id=4658) 255 | 256 | Any issues, please [report here](https://github.com/Zizaco/confide/issues) 257 | --------------------------------------------------------------------------------