diff options
author | Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> | 2013-06-13 18:09:26 +0000 |
---|---|---|
committer | Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> | 2013-06-13 18:09:26 +0000 |
commit | 313ac55539ab93110d070e17811480092d55d8ce (patch) | |
tree | 924ebbb3a13ebf107fda9c310573de1716c24217 | |
parent | cfd15eb480973e5206c83dc4f2ed18781d78f7e0 (diff) | |
parent | 6838304a85cd3b5dfdac076c600cb15f5643c674 (diff) | |
download | gitlab-ce-313ac55539ab93110d070e17811480092d55d8ce.tar.gz |
Merge branch 'feature/password_expire' of /home/git/repositories/gitlab/gitlabhq
-rw-r--r-- | app/controllers/admin/users_controller.rb | 8 | ||||
-rw-r--r-- | app/controllers/application_controller.rb | 7 | ||||
-rw-r--r-- | app/controllers/passwords_controller.rb | 38 | ||||
-rw-r--r-- | app/models/user.rb | 11 | ||||
-rw-r--r-- | app/views/admin/users/_form.html.haml | 30 | ||||
-rw-r--r-- | app/views/admin/users/show.html.haml | 112 | ||||
-rw-r--r-- | app/views/notify/new_user_email.html.haml | 9 | ||||
-rw-r--r-- | app/views/notify/new_user_email.text.erb | 5 | ||||
-rw-r--r-- | app/views/passwords/new.html.haml | 22 | ||||
-rw-r--r-- | config/routes.rb | 1 | ||||
-rw-r--r-- | db/fixtures/production/001_admin.rb | 3 | ||||
-rw-r--r-- | db/migrate/20130613165816_add_password_expires_at_to_users.rb | 5 | ||||
-rw-r--r-- | db/migrate/20130613173246_add_created_by_id_to_user.rb | 5 | ||||
-rw-r--r-- | db/schema.rb | 4 | ||||
-rw-r--r-- | spec/features/admin/admin_users_spec.rb | 18 |
15 files changed, 199 insertions, 79 deletions
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 185ad181b2a..ec3209fdfe2 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -55,8 +55,14 @@ class Admin::UsersController < Admin::ApplicationController def create admin = params[:user].delete("admin") - @admin_user = User.new(params[:user], as: :admin) + opts = { + force_random_password: true, + password_expires_at: Time.now + } + + @admin_user = User.new(params[:user].merge(opts), as: :admin) @admin_user.admin = (admin && admin.to_i > 0) + @admin_user.created_by_id = current_user.id respond_to do |format| if @admin_user.save diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 09af5b94164..fda05feefc0 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,6 +1,7 @@ class ApplicationController < ActionController::Base before_filter :authenticate_user! before_filter :reject_blocked! + before_filter :check_password_expiration before_filter :set_current_user_for_thread before_filter :add_abilities before_filter :dev_tools if Rails.env == 'development' @@ -156,4 +157,10 @@ class ApplicationController < ActionController::Base gon.gravatar_url = request.ssl? || Gitlab.config.gitlab.https ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url gon.relative_url_root = Gitlab.config.gitlab.relative_url_root end + + def check_password_expiration + if current_user && current_user.password_expires_at && current_user.password_expires_at < Time.now + redirect_to new_profile_password_path and return + end + end end diff --git a/app/controllers/passwords_controller.rb b/app/controllers/passwords_controller.rb new file mode 100644 index 00000000000..0e5b42178a7 --- /dev/null +++ b/app/controllers/passwords_controller.rb @@ -0,0 +1,38 @@ +class PasswordsController < ApplicationController + layout 'navless' + + skip_before_filter :check_password_expiration + + before_filter :set_user + before_filter :set_title + + def new + end + + def create + new_password = params[:user][:password] + new_password_confirmation = params[:user][:password_confirmation] + + result = @user.update_attributes( + password: new_password, + password_confirmation: new_password_confirmation + ) + + if result + @user.update_attributes(password_expires_at: nil) + redirect_to root_path, notice: 'Password successfully changed' + else + render :new + end + end + + private + + def set_user + @user = current_user + end + + def set_title + @title = "New password" + end +end diff --git a/app/models/user.rb b/app/models/user.rb index 0a3a40b994c..6de8d2d4c39 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -42,8 +42,11 @@ class User < ActiveRecord::Base attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, :name, :username, :skype, :linkedin, :twitter, :color_scheme_id, :theme_id, :force_random_password, - :extern_uid, :provider, as: [:default, :admin] - attr_accessible :projects_limit, :can_create_team, :can_create_group, as: :admin + :extern_uid, :provider, :password_expires_at, + as: [:default, :admin] + + attr_accessible :projects_limit, :can_create_team, :can_create_group, + as: :admin attr_accessor :force_random_password @@ -364,4 +367,8 @@ class User < ActiveRecord::Base def accessible_deploy_keys DeployKey.in_projects(self.master_projects).uniq end + + def created_by + User.find_by_id(created_by_id) if created_by_id + end end diff --git a/app/views/admin/users/_form.html.haml b/app/views/admin/users/_form.html.haml index 9bde50f8947..fdf37965091 100644 --- a/app/views/admin/users/_form.html.haml +++ b/app/views/admin/users/_form.html.haml @@ -24,19 +24,25 @@ = f.text_field :email, required: true, autocomplete: "off" %span.help-inline * required - %fieldset - %legend Password - .clearfix - = f.label :password - .input= f.password_field :password, disabled: f.object.force_random_password - .clearfix - = f.label :password_confirmation - .input= f.password_field :password_confirmation, disabled: f.object.force_random_password - -if f.object.new_record? + - if @admin_user.new_record? + %fieldset + %legend Password + .clearfix + = f.label :password + .input + %strong + A temporary password will be generated and sent to user. + %br + User will be forced to change it after first sign in + - else + %fieldset + %legend Password + .clearfix + = f.label :password + .input= f.password_field :password, disabled: f.object.force_random_password .clearfix - = f.label :force_random_password do - %span Generate random password - .input= f.check_box :force_random_password, {}, true, nil + = f.label :password_confirmation + .input= f.password_field :password_confirmation, disabled: f.object.force_random_password %fieldset %legend Access diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index 6709b8f8a6b..1b5340d687d 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -1,32 +1,65 @@ +%h3.page_title + User: + = @admin_user.name + - if @admin_user.blocked? + %span.cred (Blocked) + - if @admin_user.admin + %span.cred (Admin) + + .pull-right + = link_to edit_admin_user_path(@admin_user), class: "btn grouped btn-small" do + %i.icon-edit + Edit + - unless @admin_user == current_user + - if @admin_user.blocked? + = link_to 'Unblock', unblock_admin_user_path(@admin_user), method: :put, class: "btn grouped btn-small success" + - else + = link_to 'Block', block_admin_user_path(@admin_user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn grouped btn-small btn-remove" + = link_to 'Destroy', [:admin, @admin_user], confirm: "USER #{@admin_user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn grouped btn-small btn-remove" +%hr + .row .span6 - %h3.page_title - = image_tag gravatar_icon(@admin_user.email, 90), class: "avatar s90" - = @admin_user.name - - if @admin_user.blocked? - %span.cred (Blocked) - - if @admin_user.admin - %span.cred (Admin) - .pull-right - = link_to edit_admin_user_path(@admin_user), class: "btn pull-right" do - %i.icon-edit - Edit - %br - %small @#{@admin_user.username} - %br - %small member since #{@admin_user.created_at.stamp("Nov 12, 2031")} - .clearfix - %hr - %p - %span.btn.btn-small - %i.icon-envelope - = mail_to @admin_user.email - - unless @admin_user == current_user - - if @admin_user.blocked? - = link_to 'Unblock', unblock_admin_user_path(@admin_user), method: :put, class: "btn btn-small success" - - else - = link_to 'Block', block_admin_user_path(@admin_user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn btn-small btn-remove" - = link_to 'Destroy', [:admin, @admin_user], confirm: "USER #{@admin_user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn btn-small btn-remove" + .ui-box + %h5.title + Account: + .pull-right + = image_tag gravatar_icon(@admin_user.email, 32), class: "avatar s32" + %ul.well-list + %li + %span.light Name: + %strong= @admin_user.name + %li + %span.light Username: + %strong + = @admin_user.username + %li + %span.light Email: + %strong + = mail_to @admin_user.email + + %li + %span.light Member since: + %strong + = @admin_user.created_at.stamp("Nov 12, 2031") + + %li + %span.light Last sign-in at: + %strong + = @admin_user.last_sign_in_at.stamp("Nov 12, 2031") + + - if @admin_user.ldap_user? + %li + %span.light LDAP uid: + %strong + = @admin_user.extern_uid + + - if @admin_user.created_by + %li + %span.light Created by: + %strong + = link_to @admin_user.created_by.name, [:admin, @admin_user.created_by] + %hr %h5 Add User to Projects @@ -67,11 +100,11 @@ .span6 - = render 'users/profile', user: @admin_user .ui-box %h5.title Projects (#{@projects.count}) %ul.well-list - @projects.sort_by(&:name_with_namespace).each do |project| + - tm = project.team.get_tm(@admin_user.id) %li = link_to admin_project_path(project), class: dom_class(project) do - if project.namespace @@ -79,16 +112,17 @@ \/ %strong.well-title = truncate(project.name, length: 45) - %span.pull-right.light - - if project.owner == @admin_user - %i.icon-wrench - - tm = project.team.get_tm(@admin_user.id) - - if tm - = tm.project_access_human - = link_to edit_admin_project_member_path(project, tm.user), class: "btn btn-small" do + + - if project.owner == @admin_user + %span.label.label-info owner + + - if tm + .pull-right + = link_to edit_admin_project_member_path(project, tm.user), class: "btn grouped btn-small" do %i.icon-edit - = link_to admin_project_member_path(project, tm.user), confirm: remove_from_project_team_message(project, @admin_user), method: :delete, class: "btn btn-small btn-remove" do + = link_to admin_project_member_path(project, tm.user), confirm: remove_from_project_team_message(project, @admin_user), method: :delete, class: "btn grouped btn-small btn-remove" do %i.icon-remove - %p.light - %i.icon-wrench - – user is a project owner + + .pull-right.light + = tm.project_access_human + diff --git a/app/views/notify/new_user_email.html.haml b/app/views/notify/new_user_email.html.haml index 9804fbdd51e..fc2c02ef827 100644 --- a/app/views/notify/new_user_email.html.haml +++ b/app/views/notify/new_user_email.html.haml @@ -8,13 +8,14 @@ %p login.......................................... %code= @user['email'] -%p - - unless Gitlab.config.gitlab.signup_enabled + +- if @user.created_by_id + %p password.................................. %code= @password -%p - Please change your password immediately after login. + %p + You will be forced to change this password immediately after login. %p = link_to "Click here to login", root_url diff --git a/app/views/notify/new_user_email.text.erb b/app/views/notify/new_user_email.text.erb index 777930a2803..70fe0e0736a 100644 --- a/app/views/notify/new_user_email.text.erb +++ b/app/views/notify/new_user_email.text.erb @@ -3,10 +3,11 @@ Hi <%= @user.name %>! The Administrator created an account for you. Now you are a member of company GitLab application. login.................. <%= @user.email %> -<% unless Gitlab.config.gitlab.signup_enabled %> +<% if @user.created_by_id %> password............... <%= @password %> + + You will be forced to change this password immediately after login. <% end %> -Please change your password immediately after login. Click here to login: <%= url_for(root_url) %> diff --git a/app/views/passwords/new.html.haml b/app/views/passwords/new.html.haml new file mode 100644 index 00000000000..c92424160b3 --- /dev/null +++ b/app/views/passwords/new.html.haml @@ -0,0 +1,22 @@ += form_for @user, url: profile_password_path, method: :post do |f| + .light-well.padded + %p.slead + Please set new password before proceed. + %br + After successful password update you will be redirected to login screen + -if @user.errors.any? + .alert.alert-error + %ul + - @user.errors.full_messages.each do |msg| + %li= msg + + .clearfix + = f.label :password + .input= f.password_field :password, required: true + .clearfix + = f.label :password_confirmation + .input + = f.password_field :password_confirmation, required: true + .clearfix + .input + = f.submit 'Set new password', class: "btn btn-create" diff --git a/config/routes.rb b/config/routes.rb index 6f72e2cb186..39c79635c40 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -123,6 +123,7 @@ Gitlab::Application.routes.draw do end resource :notifications + resource :password end resources :keys diff --git a/db/fixtures/production/001_admin.rb b/db/fixtures/production/001_admin.rb index f119694d11d..632f6107b33 100644 --- a/db/fixtures/production/001_admin.rb +++ b/db/fixtures/production/001_admin.rb @@ -3,7 +3,8 @@ admin = User.create( name: "Administrator", username: 'root', password: "5iveL!fe", - password_confirmation: "5iveL!fe" + password_confirmation: "5iveL!fe", + password_expires_at: Time.now ) admin.projects_limit = 10000 diff --git a/db/migrate/20130613165816_add_password_expires_at_to_users.rb b/db/migrate/20130613165816_add_password_expires_at_to_users.rb new file mode 100644 index 00000000000..3479c8e64d0 --- /dev/null +++ b/db/migrate/20130613165816_add_password_expires_at_to_users.rb @@ -0,0 +1,5 @@ +class AddPasswordExpiresAtToUsers < ActiveRecord::Migration + def change + add_column :users, :password_expires_at, :datetime + end +end diff --git a/db/migrate/20130613173246_add_created_by_id_to_user.rb b/db/migrate/20130613173246_add_created_by_id_to_user.rb new file mode 100644 index 00000000000..615e96eb156 --- /dev/null +++ b/db/migrate/20130613173246_add_created_by_id_to_user.rb @@ -0,0 +1,5 @@ +class AddCreatedByIdToUser < ActiveRecord::Migration + def change + add_column :users, :created_by_id, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index 21e553dd612..bec32c1d52a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20130522141856) do +ActiveRecord::Schema.define(:version => 20130613173246) do create_table "deploy_keys_projects", :force => true do |t| t.integer "deploy_key_id", :null => false @@ -292,6 +292,8 @@ ActiveRecord::Schema.define(:version => 20130522141856) do t.string "state" t.integer "color_scheme_id", :default => 1, :null => false t.integer "notification_level", :default => 1, :null => false + t.datetime "password_expires_at" + t.integer "created_by_id" end add_index "users", ["admin"], :name => "index_users_on_admin" diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb index bec43e5029c..15de101a17a 100644 --- a/spec/features/admin/admin_users_spec.rb +++ b/spec/features/admin/admin_users_spec.rb @@ -20,13 +20,10 @@ describe "Admin::Users" do describe "GET /admin/users/new" do before do - @password = "123ABC" visit new_admin_user_path fill_in "user_name", with: "Big Bang" fill_in "user_username", with: "bang" fill_in "user_email", with: "bigbang@mail.com" - fill_in "user_password", with: @password - fill_in "user_password_confirmation", with: @password end it "should create new user" do @@ -57,26 +54,13 @@ describe "Admin::Users" do end it "should send valid email to user with email & password" do - Gitlab.config.gitlab.stub(:signup_enabled).and_return(false) User.observers.enable :user_observer do click_button "Create user" user = User.last email = ActionMailer::Base.deliveries.last email.subject.should have_content("Account was created") email.text_part.body.should have_content(user.email) - email.text_part.body.should have_content(@password) - end - end - - it "should send valid email to user with email without password when signup is enabled" do - Gitlab.config.gitlab.stub(:signup_enabled).and_return(true) - User.observers.enable :user_observer do - click_button "Create user" - user = User.last - email = ActionMailer::Base.deliveries.last - email.subject.should have_content("Account was created") - email.text_part.body.should have_content(user.email) - email.text_part.body.should_not have_content(@password) + email.text_part.body.should have_content('password') end end end |