Skip to content

Commit

Permalink
Merge pull request #42 from centosadmin/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
constXife authored Oct 8, 2017
2 parents a0ba5f2 + 45ecd36 commit 8443691
Show file tree
Hide file tree
Showing 25 changed files with 123 additions and 106 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ addons:

env:
- REDMINE_VER=3.3-stable
- REDMINE_VER=master

install: "echo skip bundle install"

Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# 1.3.3

* Fix missing locale 2fa
* Fix "account not found" issue with /connect bug
* Add another auth sources support (like LDAP)
* Remove old reference to MultiJSON
* Remove Telegrammer dependency

# 1.3.2

* Add reset 2fa for admin.
Expand Down
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
source 'https://rubygems.org'

gem 'telegram-bot-ruby', '<= 0.7.2'
gem 'active_model_otp'
gem 'rqrcode'

Expand Down
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ Supports:
- SMS
- Google Auth

Developed by [Centos-admin.ru](https://centos-admin.ru/)

## Requirements

- [redmine_telegram_common](https://github.com/centosadmin/redmine_telegram_common)
Expand Down Expand Up @@ -170,4 +168,4 @@ If plugin settings option "Require 2FA for each user" is switched off, user can

# Author

Developed by [Centos-admin.ru](https://centos-admin.ru/).
Developed by [Southbridge](https://southbridge.io)
4 changes: 1 addition & 3 deletions README.ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
- SMS
- Google Authenticator

Плагин разработан [Centos-admin.ru](https://centos-admin.ru/)

[Описание плагина на habrahabr.ru](https://habrahabr.ru/company/centosadmin/blog/312656/)

## Требования
Expand Down Expand Up @@ -168,4 +166,4 @@ production:

# Автор плагина

Плагин разработан [Centos-admin.ru](http://centos-admin.ru/).
Плагин разработан [Southbridge](https://southbridge.io)
27 changes: 17 additions & 10 deletions app/controllers/otp_bot_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class OtpBotController < ApplicationController

def create # init
set_bot_webhook
update_plugin_settings(@bot.me)
update_plugin_settings(@bot.api.get_me['result'])
redirect_to plugin_settings_path('redmine_2fa'), notice: t('redmine_2fa.otp_bot.init.success')
end

Expand All @@ -22,35 +22,42 @@ def update_plugin_settings(bot_info)
plugin_settings = Setting.find_by(name: 'plugin_redmine_2fa')

plugin_settings_hash = plugin_settings.value
plugin_settings_hash['bot_name'] = bot_info.username
plugin_settings_hash['bot_id'] = bot_info.id
plugin_settings_hash['bot_name'] = bot_info['username']
plugin_settings_hash['bot_id'] = bot_info['id']
plugin_settings.value = plugin_settings_hash

plugin_settings.save
end

def set_bot
@token = Redmine2FA.bot_token
@bot = Telegrammer::Bot.new(@token)
rescue MultiJson::ParseError
render_error message: t('redmine_2fa.otp_bot.init.error.wrong_token'), status: 406
rescue Telegrammer::Errors::ServiceUnavailableError
@bot = Telegram::Bot::Client.new(@token)
rescue => e
logger.error e.message
e.backtrace.each { |line| logger.error line }

render_error message: t('redmine_2fa.otp_bot.init.error.api_error'), status: 503
end

def set_bot_webhook
webhook_url = URI::HTTPS.build(host: Setting['host_name'],
path: "/redmine_2fa/bot/#{@token}/update").to_s

@bot.set_webhook(webhook_url)
@bot.api.setWebhook(url: webhook_url)
end

def reset_bot_webhook
@bot.set_webhook('')
@bot.api.setWebhook(url: '')
end

def reset_telegram_authentications
auth_source = Redmine2FA::AuthSource::Telegram.first
User.where(auth_source_id: auth_source.id).update_all(auth_source_id: nil)
User.where(two_fa_id: auth_source.id).update_all(two_fa_id: nil)
end

private

def logger
@logger ||= Redmine2FA.logger
end
end
11 changes: 11 additions & 0 deletions app/controllers/user_mobile_phone_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ def send_confirmation_code(user)
command = Redmine2FA::Configuration.sms_command
command = command.sub('%{phone}', phone).sub('%{password}', user.otp_code)
system command
rescue => e
logger.error e.message
e.backtrace.each { |line| logger.error line }

render_error message: t('redmine_2fa.second_authentications.sms.error'), status: 503
end

def set_user_from_session
Expand All @@ -30,4 +35,10 @@ def set_user_from_session
deny_access
end
end

private

def logger
@logger ||= Redmine2FA.logger
end
end
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
<p><%= form.text_field :mobile_phone %></p>
<p><%= form.text_field :mobile_phone %></p>
<% sources = (@auth_sources || []).select{|a| ['SMS', 'Telegram', 'Google Auth'].include?(a.auth_method_name)} %>
<% if sources.any? %>
<p><%= form.select :two_fa_id, ([[l(:label_internal), ""]] + sources.collect { |a| [a.name, a.id] }), {} %></p>
<% end %>
2 changes: 2 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
en:
field_two_fa: 2FA
field_mobile_phone: 'Mobile phone'
field_ignore_2fa: 'Ignore 2FA'
link_2fa_reset: Reset 2FA
Expand Down Expand Up @@ -54,6 +55,7 @@ en:
mobile_phone_submit: "Get code"
confirm_hint: enter code gotten by SMS
confirm_submit: Confirm
error: We can't send sms right now. Please, try later.

otp_bot:
init:
Expand Down
2 changes: 2 additions & 0 deletions config/locales/ru.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
ru:
field_two_fa: 2FA
field_mobile_phone: 'Мобильный телефон'
field_ignore_2fa: 'Игнорировать 2FA'
link_2fa_reset: Сбросить 2FA
Expand Down Expand Up @@ -56,6 +57,7 @@ ru:
mobile_phone_submit: "Получить код"
confirm_hint: введите код, полученный по SMS
confirm_submit: "Подтвердить"
error: Не получилось отправить смс-код, повторите, пожалуйста, попытку позднее

otp_bot:
init:
Expand Down
5 changes: 5 additions & 0 deletions db/migrate/009_add_2fa_to_users.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class Add2faToUsers < ActiveRecord::Migration
def change
add_column :users, :two_fa_id, :integer, index: true
end
end
8 changes: 5 additions & 3 deletions init.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
FileUtils.mkdir_p(Rails.root.join('log/redmine_2fa')) unless Dir.exist?(Rails.root.join('log/redmine_2fa'))

require 'redmine_2fa'
require 'telegram/bot'

ActionDispatch::Callbacks.to_prepare do
%w( /app/models/redmine_2fa/*.rb
/app/models/redmine_2fa/auth_source/*.rb
Expand All @@ -16,11 +18,11 @@

Redmine::Plugin.register :redmine_2fa do
name 'Redmine 2FA'
version '1.3.2'
version '1.3.3'
url 'https://github.com/centosadmin/redmine_2fa'
description 'Two-factor authorization for Redmine'
author 'Centos-admin.ru'
author_url 'https://centos-admin.ru'
author 'Southbridge'
author_url 'https://github.com/centosadmin/redmine_2fa'

requires_redmine version_or_higher: '3.0'

Expand Down
11 changes: 10 additions & 1 deletion lib/redmine_2fa.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,22 @@ def self.bot_token
Setting.plugin_redmine_2fa['bot_token']
end

def self.logger
Logger.new(Rails.root.join('log', 'redmine_2fa', 'bot-update.log'))
end

module Configuration
def self.configuration
Redmine::Configuration['redmine_2fa']
end

def self.sms_command
configuration && configuration['sms_command'] ? configuration['sms_command'] : 'echo %{phone} %{password} %{expired_at}'
sms_command = configuration && configuration['sms_command']
if sms_command
configuration['sms_command']
else
(Rails.env.test?) ? '' : 'echo %{phone} %{password} %{expired_at}'
end
end
end
end
2 changes: 1 addition & 1 deletion lib/redmine_2fa/code_sender.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def send_code
private

def define_sender
case user&.auth_source&.auth_method_name
case user&.two_fa&.auth_method_name
when 'Telegram'
CodeSender::TelegramSender.new(user)
when 'SMS'
Expand Down
6 changes: 3 additions & 3 deletions lib/redmine_2fa/code_sender/telegram_sender.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ def initialize(user)
def send_message
if @telegram_account.present? && @telegram_account.active?
token = Redmine2FA.bot_token
bot = Telegrammer::Bot.new(token)
bot = Telegram::Bot::Client.new(token)

message = I18n.t('redmine_2fa.telegram_auth.message',
app_title: Setting.app_title, code: code, expiration_time: timestamp)

bot.send_message(chat_id: @telegram_account.telegram_id, text: message)
bot.api.send_message(chat_id: @telegram_account.telegram_id, text: message)
end
rescue Telegrammer::Errors::BadRequestError => e
rescue Telegram::Bot::Exceptions::ResponseError => e
errors << "Telegram Bot API: #{e.message}"
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ def self.included(base) # :nodoc:
module InstanceMethods
def confirm_2fa
if protocol == 'none'
@user.update!(ignore_2fa: true)
@user.update!(ignore_2fa: true, two_fa: nil)
reset_otp_session
successful_authentication(@user)
else
update_auth_source
update_two_fa
Redmine2FA::CodeSender.new(@user).send_code
render 'account/otp'
end
Expand Down Expand Up @@ -52,13 +52,13 @@ def set_user_from_session
end
end

def update_auth_source
@user.update_columns(auth_source_id: auth_source.id) if auth_source
def update_two_fa
@user.update_columns(two_fa_id: two_fa.id) if two_fa
end

def auth_source
def two_fa
return unless Redmine2FA.active_protocols.include?(protocol)
@auth_source ||= "Redmine2FA::AuthSource::#{auth_source_class}".constantize.first
@two_fa ||= "Redmine2FA::AuthSource::#{auth_source_class}".constantize.first
end

def auth_source_class
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def password_authentication
if Redmine2FA.switched_off? || @user.ignore_2fa? || @user.two_factor_authenticable?
super
else
@qr = RQRCode::QRCode.new(@user.provisioning_uri("#{@user.login}@#{Setting.host_name}"), size: 8, level: :h)
@qr = RQRCode::QRCode.new(@user.provisioning_uri("#{@user.login}", issuer: "#{Setting.host_name}"), size: 10, level: :h)
render 'account/init_2fa'
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ module SecondAuthenticationPrepare
private

def password_authentication
@user = User.find_by_login(params[:username])
@user = User.try_to_login(params[:username], params[:password], false)

if @user && User.try_to_login(params[:username], params[:password])
if @user.nil?
invalid_credentials
elsif @user.new_record?
onthefly_creation_failed(@user, { login: @user.login, auth_source_id: @user.auth_source_id })
else
set_otp_session
super
else
invalid_credentials
end
end

Expand Down
14 changes: 8 additions & 6 deletions lib/redmine_2fa/patches/user_patch.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module Patches
module UserPatch
def self.included(base)
base.send(:include, InstanceMethods)
base.safe_attributes 'mobile_phone', 'ignore_2fa'
base.safe_attributes 'mobile_phone', 'ignore_2fa', 'two_fa_id'
base.validates_format_of :mobile_phone, with: /\A\d*\z/, allow_blank: true

base.class_eval do
Expand All @@ -12,6 +12,8 @@ def self.included(base)
has_one_time_password length: 6

alias_method_chain :update_hashed_password, :otp_auth

belongs_to :two_fa, class_name: 'AuthSource'
end
end

Expand All @@ -25,24 +27,24 @@ def update_hashed_password_with_otp_auth
end

def two_factor_authenticable?
telegram_authenticable? || sms_authenticable? || google_authenticable?
two_fa
end

def sms_authenticable?
auth_source&.auth_method_name == 'SMS'
two_fa&.auth_method_name == 'SMS'
end

def telegram_authenticable?
auth_source&.auth_method_name == 'Telegram'
two_fa&.auth_method_name == 'Telegram'
end

def google_authenticable?
auth_source&.auth_method_name == 'Google Auth'
two_fa&.auth_method_name == 'Google Auth'
end

def reset_second_auth
otp_regenerate_secret
self.auth_source_id = nil
self.two_fa_id = nil
self.ignore_2fa = false
save!
end
Expand Down
Loading

0 comments on commit 8443691

Please sign in to comment.