parent
6408f0884e
commit
37c5f322e6
@ -1,3 +1,3 @@ |
|||||||
FROM redmine:latest-alpine |
FROM redmine:latest |
||||||
ENV REDMINE_DB_PASSWORD=${MYSQL_ROOT_PASSWORD} |
ENV REDMINE_DB_PASSWORD=${MYSQL_ROOT_PASSWORD} |
||||||
COPY ./redmine_ldap_passwd/. /usr/share/redmine/plugins/ |
ADD ./redmine_ldap_passwd/ /usr/share/redmine/plugins/ |
@ -1,3 +1,3 @@ |
|||||||
FROM redmine |
FROM redmine:latest |
||||||
ENV REDMINE_DB_PASSWORD=${MYSQL_ROOT_PASSWORD} |
ENV REDMINE_DB_PASSWORD=${MYSQL_ROOT_PASSWORD} |
||||||
COPY ./redmine_ldap_passwd/. /usr/share/redmine/plugins/ |
COPY redmine_ldap_passwd /usr/share/redmine/plugins/ |
@ -1,27 +0,0 @@ |
|||||||
# Redmine LDAP Passwd plugin >= Redmine 3.0 |
|
||||||
|
|
||||||
The plugin extends AuthSourceLdap to introduce the ability to recover or change user password. |
|
||||||
|
|
||||||
### Features |
|
||||||
|
|
||||||
* Allows to changed password and update LDAP record. |
|
||||||
* Allows to recover password and update LDAP record. |
|
||||||
|
|
||||||
**Notes** |
|
||||||
|
|
||||||
* The solution has been tested on MS Active Directory only. It works only with SSL connection, please ensure SSL is configured on Active Directory side. |
|
||||||
|
|
||||||
### Install |
|
||||||
|
|
||||||
1. Follow Redmine [plugin installation instructions](http://www.redmine.org/projects/redmine/wiki/Plugins#Installing-a-plugin). |
|
||||||
2. Add new LDAP connection and check the records in 'auth_sources' making sure column 'type'='AuthSourceLdapPasswd'. If it is not, update the record manually executing the SQL query. |
|
||||||
3. Assign new LDAP connection to the specific users you would like to provide access through LDAP to. |
|
||||||
|
|
||||||
### Uninstall |
|
||||||
|
|
||||||
1. Follow Redmine [plugin uninstall instructions](http://www.redmine.org/projects/redmine/wiki/Plugins#Uninstalling-a-plugin). |
|
||||||
|
|
||||||
### Changelog |
|
||||||
|
|
||||||
* **3.0 (2016-05-31)** |
|
||||||
* Initial version released. |
|
@ -1,57 +0,0 @@ |
|||||||
class AuthSourceLdapPasswd < AuthSourceLdap |
|
||||||
def allow_password_changes? |
|
||||||
self.tls |
|
||||||
end |
|
||||||
|
|
||||||
def change_user_password(user, password, new_password) |
|
||||||
return false unless AuthSourceLdapPasswd.change_password_allowed?(user) |
|
||||||
|
|
||||||
attrs = get_user_dn(user.login, password) |
|
||||||
if attrs && attrs[:dn] |
|
||||||
if self.account && self.account.include?("$login") |
|
||||||
ldap_con = initialize_ldap_con(self.account.sub("$login", Net::LDAP::DN.escape(user.login)), password) |
|
||||||
else |
|
||||||
ldap_con = initialize_ldap_con(self.account, self.account_password) |
|
||||||
end |
|
||||||
|
|
||||||
ops = [[:replace, :unicodePwd, AuthSourceLdapPasswd.str2unicodePwd(new_password)]] |
|
||||||
ldap_con.modify :dn => attrs[:dn], :operations => ops |
|
||||||
|
|
||||||
result = ldap_con.get_operation_result |
|
||||||
if result.code == 0 |
|
||||||
user.passwd_changed_on = Time.now.change(:usec => 0) |
|
||||||
user.save |
|
||||||
|
|
||||||
return true |
|
||||||
else |
|
||||||
return result |
|
||||||
end |
|
||||||
end |
|
||||||
|
|
||||||
false |
|
||||||
end |
|
||||||
|
|
||||||
def self.str2unicodePwd(str) |
|
||||||
('"' + str + '"').encode("utf-16le").force_encoding("utf-8") |
|
||||||
end |
|
||||||
|
|
||||||
def self.change_password_allowed?(user) |
|
||||||
return false if user.nil? |
|
||||||
AuthSourceLdapPasswd.name.eql?(user.auth_source.type) |
|
||||||
end |
|
||||||
|
|
||||||
def self.is_password_valid(password) |
|
||||||
return false if password.nil? || password.length < 7 |
|
||||||
|
|
||||||
s = 0 |
|
||||||
contains = [ |
|
||||||
password.match(/\p{Lower}/) ? 1 : 0, |
|
||||||
password.match(/\p{Upper}/) ? 1 : 0, |
|
||||||
password.match(/\p{Digit}/) ? 1 : 0, |
|
||||||
password.match(/[^\\w\\d]+/) ? 1 : 0 |
|
||||||
] |
|
||||||
contains.each { |a| s += a } |
|
||||||
|
|
||||||
return s >= 3 |
|
||||||
end |
|
||||||
end |
|
@ -1,3 +0,0 @@ |
|||||||
en: |
|
||||||
notice_new_password_and_confirmation_different: The new password is different from the confirmation password |
|
||||||
notice_new_password_format: "1. The password should be at least seven characters long. 2. The password should contain characters from at least three of the following four categories: (a) English uppercase characters (A - Z) (b) English lowercase characters (a - z) (c) Base 10 digits (0 - 9) (d) Non-alphanumeric (For example: !, $, or %). 3. The password shouldn't contain three or more characters from the user's account name." |
|
@ -1,36 +0,0 @@ |
|||||||
require 'redmine' |
|
||||||
|
|
||||||
require_dependency 'redmine_ldap_passwd_my_controller_patch' |
|
||||||
require_dependency 'redmine_ldap_passwd_auth_sources_helper_patch' |
|
||||||
require_dependency 'redmine_ldap_passwd_account_controller_patch' |
|
||||||
|
|
||||||
Redmine::Plugin.register :redmine_ldap_passwd do |
|
||||||
name 'Redmine LDAP Change Password' |
|
||||||
author 'Yura Zaplavnov' |
|
||||||
description 'The plugin extends AuthSourceLdap to introduce the ability to recover or change user password.' |
|
||||||
version '3.0.1' |
|
||||||
url 'https://github.com/xeagle2/redmine_ldap_passwd' |
|
||||||
author_url 'https://github.com/xeagle2' |
|
||||||
end |
|
||||||
|
|
||||||
require 'dispatcher' unless Rails::VERSION::MAJOR >= 3 |
|
||||||
|
|
||||||
if Rails::VERSION::MAJOR >= 5 |
|
||||||
ActiveSupport::Reloader.to_prepare do |
|
||||||
MyController.send(:include, RedmineLdapPasswd::MyControllerPatch) |
|
||||||
AuthSourcesHelper.send(:include, RedmineLdapPasswd::AuthSourcesHelperPatch) |
|
||||||
AccountController.send(:include, RedmineLdapPasswd::AccountControllerPatch) |
|
||||||
end |
|
||||||
elsif Rails::VERSION::MAJOR >= 3 |
|
||||||
ActionDispatch::Callbacks.to_prepare do |
|
||||||
MyController.send(:include, RedmineLdapPasswd::MyControllerPatch) |
|
||||||
AuthSourcesHelper.send(:include, RedmineLdapPasswd::AuthSourcesHelperPatch) |
|
||||||
AccountController.send(:include, RedmineLdapPasswd::AccountControllerPatch) |
|
||||||
end |
|
||||||
else |
|
||||||
Dispatcher.to_prepare do |
|
||||||
MyController.send(:include, RedmineLdapPasswd::MyControllerPatch) |
|
||||||
AuthSourcesHelper.send(:include, RedmineLdapPasswd::AuthSourcesHelperPatch) |
|
||||||
AccountController.send(:include, RedmineLdapPasswd::AccountControllerPatch) |
|
||||||
end |
|
||||||
end |
|
@ -1,66 +0,0 @@ |
|||||||
module RedmineLdapPasswd |
|
||||||
module AccountControllerPatch |
|
||||||
def self.included(base) |
|
||||||
base.send(:extend, ClassMethods) |
|
||||||
base.send(:include, InstanceMethods) |
|
||||||
|
|
||||||
base.class_eval do |
|
||||||
unloadable # Send unloadable so it will not be unloaded in development |
|
||||||
|
|
||||||
if Rails::VERSION::MAJOR >= 5 |
|
||||||
alias_method :lost_password_without_extension, :lost_password |
|
||||||
alias_method :lost_password, :lost_password_with_extension |
|
||||||
else |
|
||||||
alias_method :lost_password, :extension |
|
||||||
end |
|
||||||
end |
|
||||||
end |
|
||||||
|
|
||||||
module ClassMethods |
|
||||||
end |
|
||||||
|
|
||||||
module InstanceMethods |
|
||||||
def lost_password_with_extension |
|
||||||
if params[:token] |
|
||||||
@token = Token.find_token("recovery", params[:token].to_s) |
|
||||||
if @token.nil? || @token.expired? |
|
||||||
redirect_to home_url |
|
||||||
return |
|
||||||
end |
|
||||||
|
|
||||||
@user = @token.user |
|
||||||
unless @user && @user.active? |
|
||||||
redirect_to home_url |
|
||||||
return |
|
||||||
end |
|
||||||
|
|
||||||
if request.post? |
|
||||||
if params[:new_password_confirmation] != params[:new_password] |
|
||||||
flash.now[:error] = l(:notice_new_password_and_confirmation_different) |
|
||||||
elsif !AuthSourceLdapPasswd.is_password_valid (params[:new_password]) |
|
||||||
flash.now[:error] = l(:notice_new_password_format) |
|
||||||
else |
|
||||||
r = @user.auth_source.change_user_password(@user, '', params[:new_password]) |
|
||||||
|
|
||||||
if r == true |
|
||||||
flash[:notice] = l(:notice_account_password_updated) |
|
||||||
redirect_to signin_path |
|
||||||
elsif r == false |
|
||||||
lost_password_without_extension |
|
||||||
else |
|
||||||
flash.now[:error] = r.message |
|
||||||
end |
|
||||||
|
|
||||||
return |
|
||||||
end |
|
||||||
end |
|
||||||
|
|
||||||
render :template => "account/password_recovery" |
|
||||||
return |
|
||||||
else |
|
||||||
lost_password_without_extension |
|
||||||
end |
|
||||||
end |
|
||||||
end |
|
||||||
end |
|
||||||
end |
|
@ -1,25 +0,0 @@ |
|||||||
module RedmineLdapPasswd |
|
||||||
module AuthSourcesHelperPatch |
|
||||||
def self.included(base) # :nodoc: |
|
||||||
base.send(:include, InstanceMethods) |
|
||||||
|
|
||||||
base.class_eval do |
|
||||||
unloadable # Send unloadable so it will not be unloaded in development |
|
||||||
|
|
||||||
if Rails::VERSION::MAJOR >= 5 |
|
||||||
alias_method :auth_source_partial_name_without_ignored_passwd, :auth_source_partial_name |
|
||||||
alias_method :auth_source_partial_name, :auth_source_partial_name_with_ignored_passwd |
|
||||||
else |
|
||||||
alias_method :auth_source_partial_name, :ignored_passwd |
|
||||||
end |
|
||||||
end |
|
||||||
end |
|
||||||
|
|
||||||
module InstanceMethods |
|
||||||
# Make sure AuthSourceLdapPasswd is loaded with the same form as AuthSourceLdap |
|
||||||
def auth_source_partial_name_with_ignored_passwd(auth_source) |
|
||||||
"form_#{auth_source.class.name.underscore}".chomp('_passwd') |
|
||||||
end |
|
||||||
end |
|
||||||
end |
|
||||||
end |
|
@ -1,64 +0,0 @@ |
|||||||
module RedmineLdapPasswd |
|
||||||
module MyControllerPatch |
|
||||||
def self.included(base) |
|
||||||
base.send(:extend, ClassMethods) |
|
||||||
base.send(:include, InstanceMethods) |
|
||||||
|
|
||||||
base.class_eval do |
|
||||||
unloadable # Send unloadable so it will not be unloaded in development |
|
||||||
|
|
||||||
if Rails::VERSION::MAJOR >= 5 |
|
||||||
alias_method :password_without_extension, :password |
|
||||||
alias_method :password, :password_with_extension |
|
||||||
else |
|
||||||
alias_method_chain :password, :extension |
|
||||||
end |
|
||||||
end |
|
||||||
end |
|
||||||
|
|
||||||
module ClassMethods |
|
||||||
end |
|
||||||
|
|
||||||
module InstanceMethods |
|
||||||
def password_with_extension |
|
||||||
@user = User.current |
|
||||||
|
|
||||||
unless @user.change_password_allowed? |
|
||||||
flash[:error] = l(:notice_can_t_change_password) |
|
||||||
redirect_to my_account_path |
|
||||||
return |
|
||||||
end |
|
||||||
|
|
||||||
if request.post? |
|
||||||
if !@user.check_password?(params[:password]) |
|
||||||
flash.now[:error] = l(:notice_account_wrong_password) |
|
||||||
elsif params[:password] == params[:new_password] |
|
||||||
flash.now[:error] = l(:notice_new_password_must_be_different) |
|
||||||
elsif params[:new_password_confirmation] != params[:new_password] |
|
||||||
flash.now[:error] = l(:notice_new_password_and_confirmation_different) |
|
||||||
elsif AuthSourceLdapPasswd.change_password_allowed?(@user) |
|
||||||
if AuthSourceLdapPasswd.is_password_valid (params[:new_password]) |
|
||||||
r = @user.auth_source.change_user_password(@user, params[:password], params[:new_password]) |
|
||||||
|
|
||||||
if r == true |
|
||||||
session[:ctime] = User.current.passwd_changed_on.utc.to_i |
|
||||||
flash[:notice] = l(:notice_account_password_updated) |
|
||||||
redirect_to my_account_path |
|
||||||
elsif r == false |
|
||||||
password_without_extension |
|
||||||
else |
|
||||||
flash.now[:error] = r.message |
|
||||||
end |
|
||||||
else |
|
||||||
flash.now[:error] = l(:notice_new_password_format) |
|
||||||
end |
|
||||||
else |
|
||||||
password_without_extension |
|
||||||
end |
|
||||||
end |
|
||||||
rescue Net::LDAP::LdapError => e |
|
||||||
raise AuthSourceException.new(e.message) |
|
||||||
end |
|
||||||
end |
|
||||||
end |
|
||||||
end |
|
Loading…
Reference in new issue