Gestión de usuarios en gitlab desde la consola rails

Esta semana tuve que dar soporte a un viejo servidor GitLab 6.0 y nadie tenía la contraseña del usuario admin. Así que me vi en la necesidad de usar la consola de rails para crear un usuario local y asignarle permisos de administrador en GitLab. Desde la rails console es posible realizar multitud de gestiones aunque en esta entrada tan solo nos centraremos en la creación de usuarios, reseteo de contraseña y asignación de permisos de administrador en GitLab.

Dependiendo de la versión de GitLab algunos parámetros no son permitidos, siendo necesario hacer algunas acciones en dos pasos.

Lanzar la consola rails

Dependiendo del GitLab, la consola puede ser invocada con el usuario root desde cualquier directorio usando el comando gitlab-rails console production o debe ser invocada con el usuario git en el directorio gitlab usando el comando bundle exec rails console production. A continuación ambos ejemplos:

  • A través de gitlab-rails:

    1
    2
    3
    [root@git ~]# gitlab-rails console production
    Loading production environment (Rails 4.2.8)
    irb(main):001:0>
  • A través de bundle exec:

    1
    2
    3
    git@gitlab-prod:~/gitlab[6-0-stable]$ bundle exec rails console production
    Loading production environment (Rails 3.2.13)
    1.9.1 :001 >

Crear usuario

1
2
3
4
5
6
7
User.create(
:username => 'antonio.guillen',
:name => 'Antonio Guillen (local)',
:password => '12345678',
:password_confirmation => '12345678',
:email => 'antonio@guillen.io',
:admin => true)

En GitLab 6.0 el comando User.create no admite el parámetros admin, el cual activa el flag de administrador de GitLab. Por lo que será necesario, primero crear el usuario y, posteriormente asignarle permisos de administrador.

A continuación un ejemplo de la salida del comando User.create en GitLab 6.0:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1.9.1 :001 > User.create(:username => 'antonio.guillen', :name => 'Antonio Guillen (local)', :password => '12345678', :password_confirmation => '12345678', :email => 'antonio@guillen.io')
(0.2ms) BEGIN
User Exists (0.2ms) SELECT 1 AS one FROM `users` WHERE `users`.`email` = BINARY 'antonio@guillen.io' LIMIT 1
User Exists (0.1ms) SELECT 1 AS one FROM `users` WHERE `users`.`username` = BINARY 'antonio.guillen' LIMIT 1
Namespace Load (0.1ms) SELECT `namespaces`.* FROM `namespaces` WHERE `namespaces`.`path` = 'antonio.guillen' LIMIT 1
User Load (0.7ms) SELECT `users`.* FROM `users` WHERE `users`.`authentication_token` = 'XfZkqzg6WypNS43z8Lv4' LIMIT 1
SQL (17.4ms) INSERT INTO `users` (`admin`, `authentication_token`, `bio`, `can_create_group`, `can_create_team`, `color_scheme_id`, `created_at`, `created_by_id`, `current_sign_in_at`, `current_sign_in_ip`, `email`, `encrypted_password`, `extern_uid`, `failed_attempts`, `last_sign_in_at`, `last_sign_in_ip`, `linkedin`, `locked_at`, `name`, `notification_level`, `password_expires_at`, `projects_limit`, `provider`, `remember_created_at`, `reset_password_sent_at`, `reset_password_token`, `sign_in_count`, `skype`, `state`, `theme_id`, `twitter`, `updated_at`, `username`) VALUES (0, 'XfZkqzg6WypNS43z8Lv4', NULL, 1, 1, 1, '2017-05-12 09:25:52', NULL, NULL, NULL, 'antonio@guillen.io', '$2a$10$mALM7bf/beG8kMiDKcmHseZw/2CILMa6iimO.4uZn9e1b06TRCJkW', NULL, 0, NULL, NULL, '', NULL, 'Antonio Guillen (local)', 1, NULL, 10, NULL, NULL, NULL, NULL, 0, '', 'active', 1, '', '2017-05-12 09:25:52', 'antonio.guillen')
SystemHook Load (0.4ms) SELECT `web_hooks`.* FROM `web_hooks` WHERE `web_hooks`.`type` IN ('SystemHook')
2017-05-12T09:25:52Z 32616 TID-bfp4k INFO: Sidekiq client using redis://localhost:6379 with options {:namespace=>"resque:gitlab"}
Namespace Load (0.9ms) SELECT `namespaces`.* FROM `namespaces` WHERE `namespaces`.`owner_id` = 583 AND (type IS NULL) LIMIT 1
User Load (0.8ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 583 LIMIT 1
Namespace Exists (0.7ms) SELECT 1 AS one FROM `namespaces` WHERE `namespaces`.`name` = BINARY 'antonio.guillen' LIMIT 1
Namespace Exists (0.4ms) SELECT 1 AS one FROM `namespaces` WHERE `namespaces`.`path` = BINARY 'antonio.guillen' LIMIT 1
SQL (0.9ms) INSERT INTO `namespaces` (`created_at`, `description`, `name`, `owner_id`, `path`, `type`, `updated_at`) VALUES ('2017-05-12 09:25:52', '', 'antonio.guillen', 583, 'antonio.guillen', NULL, '2017-05-12 09:25:52')
Namespace Exists (0.8ms) SELECT 1 AS one FROM `namespaces` WHERE (`namespaces`.`name` = BINARY 'Antonio Guillen (local)' AND `namespaces`.`id` != 613) LIMIT 1
Namespace Exists (0.7ms) SELECT 1 AS one FROM `namespaces` WHERE (`namespaces`.`path` = BINARY 'antonio.guillen' AND `namespaces`.`id` != 613) LIMIT 1
(64.5ms) COMMIT
=> #<User id: 583, email: "antonio@guillen.io", encrypted_password: "$2a$10$mALM7bf/beG8kMiDKcmHseZw/2CILMa6iimO.4uZn9e1...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, created_at: "2017-05-12 09:25:52", updated_at: "2017-05-12 09:25:52", name: "Antonio Guillen (local)", admin: false, projects_limit: 10, skype: "", linkedin: "", twitter: "", authentication_token: "XfZkqzg6WypNS43z8Lv4", theme_id: 1, bio: nil, failed_attempts: 0, locked_at: nil, extern_uid: nil, provider: nil, username: "antonio.guillen", can_create_group: true, can_create_team: true, state: "active", color_scheme_id: 1, notification_level: 1, password_expires_at: nil, created_by_id: nil>

A continuación un ejemplo de la salida del comando User.create en GitLab 9.1:

1
2
3
4
5
6
7
8
9
irb(main):001:0> User.create(
irb(main):002:1* :username => 'antonio.guillen',
irb(main):003:1* :name => 'Antonio Guillen (local)',
irb(main):004:1* :password => '12345678',
irb(main):005:1* :password_confirmation => '12345678',
irb(main):006:1* :email => 'antonio@guillen.io',
irb(main):007:1* :admin => true)
Enqueued ActionMailer::DeliveryJob (Job ID: 4d00eedc-f543-4ae5-b2d1-9f8263bc0909) to Sidekiq(mailers) with arguments: "DeviseMailer", "confirmation_instructions", "deliver_now", gid://gitlab/User/14, "7scVCZbBQxGBPF-vcMwP", {}
=> #<User id: 9856, email: "antonio@guillen.io", created_at: "2017-05-11 14:46:12", updated_at: "2017-05-12 18:01:14", name: "Antonio Guillen (local)", admin: true, projects_limit: 10, skype: "", linkedin: "", twitter: "", authentication_token: "XxUaRK68MbHUr-5zxydQ", bio: nil, username: "antonio.guillen", can_create_group: true, can_create_team: false, state: "active", color_scheme_id: 1, password_expires_at: nil, created_by_id: nil, last_credential_check_at: nil, avatar: nil, hide_no_ssh_key: false, website_url: "", notification_email: "antonio@guillen.io", hide_no_password: false, password_automatically_set: false, location: nil, encrypted_otp_secret: nil, encrypted_otp_secret_iv: nil, encrypted_otp_secret_salt: nil, otp_required_for_login: false, otp_backup_codes: nil, public_email: "", dashboard: 0, project_view: 2, consumed_timestep: nil, layout: 0, hide_project_limit: false, otp_grace_period_started_at: nil, ldap_email: false, external: false, organization: nil, incoming_email_token: "ooy57xbplg17jx0l8divf5uc", authorized_projects_populated: nil, ghost: nil, require_two_factor_authentication_from_group: false, two_factor_grace_period: 48, last_activity_on: nil, notified_of_own_activity: false>

Asignar permisos de administrador a un usuario

1
2
3
u = User.find_by_username("antonio.guillen")
u.admin=true
u.save

A continuación un ejemplo en GitLab 6.0:

1
2
3
4
5
6
7
8
9
10
11
12
1.9.1 :002 > u = User.find_by_username("antonio.guillen")
User Load (1.0ms) SELECT `users`.* FROM `users` WHERE `users`.`username` = 'antonio.guillen' LIMIT 1
=> #<User id: 583, email: "antonio@guillen.io", encrypted_password: "$2a$10$kSdnCDNYo/.8bKnabxgvQeCG.ZTNGWDdskMwZsHLWhTB...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 1, current_sign_in_at: "2017-05-12 09:27:02", last_sign_in_at: "2017-05-12 09:27:02", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", created_at: "2017-05-12 09:25:52", updated_at: "2017-05-12 09:27:30", name: "Antonio Guillen (local)", admin: false, projects_limit: 10, skype: "", linkedin: "", twitter: "", authentication_token: "XfZkqzg6WypNS43z8Lv4", theme_id: 1, bio: nil, failed_attempts: 0, locked_at: nil, extern_uid: nil, provider: nil, username: "antonio.guillen", can_create_group: true, can_create_team: true, state: "active", color_scheme_id: 1, notification_level: 1, password_expires_at: nil, created_by_id: nil>
1.9.1 :003 > u.admin=true
=> true
1.9.1 :004 > u.save
(0.1ms) BEGIN
User Exists (0.7ms) SELECT 1 AS one FROM `users` WHERE (`users`.`username` = BINARY 'antonio.guillen' AND `users`.`id` != 583) LIMIT 1
(0.9ms) UPDATE `users` SET `admin` = 1, `updated_at` = '2017-05-12 09:36:33' WHERE `users`.`id` = 583
Namespace Load (0.4ms) SELECT `namespaces`.* FROM `namespaces` WHERE `namespaces`.`owner_id` = 583 AND (type IS NULL) LIMIT 1
(41.8ms) COMMIT
=> true

Confirmar un usuario

Es posible confirmar un usuario sin pasar por el proceso de activación vía email:

1
2
3
4
user = User.find_by(username: 'antonio.guillen')
user.confirmed_at = Time.now
user.confirmation_token = nil
user.save!

A continuación un ejemplo en GitLab 9.1:

1
2
3
4
5
6
7
8
irb(main):001:0> user = User.find_by(username: 'antonio.guillen')
=> #<User id: 9856, email: "antonio@guillen.io", created_at: "2017-05-11 14:46:12", updated_at: "2017-05-11 14:46:44", name: "Antonio Guillen (local)", admin: true, projects_limit: 10, skype: "", linkedin: "", twitter: "", authentication_token: "DxFDtxCMavx9q7113fCS", bio: nil, username: "antonio.guillen", can_create_group: true, can_create_team: false, state: "active", color_scheme_id: 1, password_expires_at: nil, created_by_id: nil, last_credential_check_at: nil, avatar: nil, hide_no_ssh_key: false, website_url: "", notification_email: "antonio@guillen.io", hide_no_password: false, password_automatically_set: false, location: nil, encrypted_otp_secret: nil, encrypted_otp_secret_iv: nil, encrypted_otp_secret_salt: nil, otp_required_for_login: false, otp_backup_codes: nil, public_email: "", dashboard: 0, project_view: 2, consumed_timestep: nil, layout: 0, hide_project_limit: false, otp_grace_period_started_at: nil, ldap_email: false, external: false, organization: nil, incoming_email_token: "9ibe7lkf46cd7q38c8lle4qh1", authorized_projects_populated: nil, ghost: nil, require_two_factor_authentication_from_group: false, two_factor_grace_period: 48, last_activity_on: nil, notified_of_own_activity: false>
irb(main):037:0> user.confirmed_at = Time.now
=> 2017-05-11 16:57:23 +0200
irb(main):002:0> user.confirmation_token = nil
=> nil
irb(main):003:0> user.save!
=> true

Más información

Entradas de interés

Contenidos
  1. 1. Lanzar la consola rails
  2. 2. Crear usuario
  3. 3. Asignar permisos de administrador a un usuario
  4. 4. Confirmar un usuario
  5. 5. Más información