Merge remote-tracking branch 'chiliproject/master' into unstable
This commit is contained in:
commit
d24e8186b4
@ -20,9 +20,9 @@ class AccountController < ApplicationController
|
|||||||
|
|
||||||
# Login request and validation
|
# Login request and validation
|
||||||
def login
|
def login
|
||||||
if request.get?
|
if User.current.logged?
|
||||||
logout_user
|
redirect_to home_url
|
||||||
else
|
elsif request.post?
|
||||||
authenticate_user
|
authenticate_user
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -173,6 +173,7 @@ class WikiController < ApplicationController
|
|||||||
def annotate
|
def annotate
|
||||||
@annotate = @page.annotate(params[:version])
|
@annotate = @page.annotate(params[:version])
|
||||||
render_404 unless @annotate
|
render_404 unless @annotate
|
||||||
|
@editable = editable?
|
||||||
end
|
end
|
||||||
|
|
||||||
verify :method => :delete, :only => [:destroy], :redirect_to => { :action => :show }
|
verify :method => :delete, :only => [:destroy], :redirect_to => { :action => :show }
|
||||||
|
@ -21,6 +21,7 @@ class AuthSourceLdap < AuthSource
|
|||||||
validates_length_of :account, :account_password, :base_dn, :maximum => 255, :allow_nil => true
|
validates_length_of :account, :account_password, :base_dn, :maximum => 255, :allow_nil => true
|
||||||
validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30, :allow_nil => true
|
validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30, :allow_nil => true
|
||||||
validates_numericality_of :port, :only_integer => true
|
validates_numericality_of :port, :only_integer => true
|
||||||
|
validate :custom_filter_should_be_valid_ldap_filter_syntax
|
||||||
|
|
||||||
before_validation :strip_ldap_attributes
|
before_validation :strip_ldap_attributes
|
||||||
|
|
||||||
@ -101,10 +102,17 @@ class AuthSourceLdap < AuthSource
|
|||||||
ldap_con = initialize_ldap_con(self.account, self.account_password)
|
ldap_con = initialize_ldap_con(self.account, self.account_password)
|
||||||
login_filter = Net::LDAP::Filter.eq( self.attr_login, login )
|
login_filter = Net::LDAP::Filter.eq( self.attr_login, login )
|
||||||
object_filter = Net::LDAP::Filter.eq( "objectClass", "*" )
|
object_filter = Net::LDAP::Filter.eq( "objectClass", "*" )
|
||||||
attrs = {}
|
custom_ldap_filter = custom_filter_to_ldap
|
||||||
|
|
||||||
ldap_con.search( :base => self.base_dn,
|
if custom_ldap_filter.present?
|
||||||
:filter => object_filter & login_filter,
|
search_filters = object_filter & login_filter & custom_ldap_filter
|
||||||
|
else
|
||||||
|
search_filters = object_filter & login_filter
|
||||||
|
end
|
||||||
|
attrs = {}
|
||||||
|
|
||||||
|
ldap_con.search( :base => self.base_dn,
|
||||||
|
:filter => search_filters,
|
||||||
:attributes=> search_attributes) do |entry|
|
:attributes=> search_attributes) do |entry|
|
||||||
|
|
||||||
if onthefly_register?
|
if onthefly_register?
|
||||||
@ -119,6 +127,27 @@ class AuthSourceLdap < AuthSource
|
|||||||
attrs
|
attrs
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def custom_filter_to_ldap
|
||||||
|
return nil unless custom_filter.present?
|
||||||
|
|
||||||
|
begin
|
||||||
|
return Net::LDAP::Filter.construct(custom_filter)
|
||||||
|
rescue Net::LDAP::LdapError # Filter syntax error
|
||||||
|
logger.debug "LDAP custom filter syntax error for: #{custom_filter}" if logger && logger.debug?
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def custom_filter_should_be_valid_ldap_filter_syntax
|
||||||
|
return true unless custom_filter.present?
|
||||||
|
|
||||||
|
begin
|
||||||
|
return Net::LDAP::Filter.construct(custom_filter)
|
||||||
|
rescue Net::LDAP::LdapError # Filter syntax error
|
||||||
|
errors.add(:custom_filter, :invalid)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def self.get_attr(entry, attr_name)
|
def self.get_attr(entry, attr_name)
|
||||||
if !attr_name.blank?
|
if !attr_name.blank?
|
||||||
entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name]
|
entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name]
|
||||||
|
@ -25,6 +25,9 @@
|
|||||||
|
|
||||||
<p><label for="auth_source_onthefly_register"><%=l(:field_onthefly)%></label>
|
<p><label for="auth_source_onthefly_register"><%=l(:field_onthefly)%></label>
|
||||||
<%= check_box 'auth_source', 'onthefly_register' %></p>
|
<%= check_box 'auth_source', 'onthefly_register' %></p>
|
||||||
|
|
||||||
|
<p><label for="auth_source_custom_filter"><%=l(:field_custom_filter)%></label>
|
||||||
|
<%= text_field 'auth_source', 'custom_filter', :size => 60 %></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<fieldset class="box"><legend><%=l(:label_attribute_plural)%></legend>
|
<fieldset class="box"><legend><%=l(:label_attribute_plural)%></legend>
|
||||||
|
@ -1,6 +1,13 @@
|
|||||||
<div class="contextual">
|
<div class="contextual">
|
||||||
<%= link_to(l(:button_edit), {:action => 'edit', :id => @page.title}, :class => 'icon icon-edit') %>
|
<% if @editable %>
|
||||||
<%= link_to(l(:label_history), {:action => 'history', :id => @page.title}, :class => 'icon icon-history') %>
|
<%= link_to_if_authorized(l(:button_edit), {:action => 'edit', :id => @page.title}, :class => 'icon icon-edit', :accesskey => accesskey(:edit)) if @annotate.content.version == @page.content.version %>
|
||||||
|
<%= watcher_link(@page, User.current) %>
|
||||||
|
<%= link_to_if_authorized(l(:button_lock), {:action => 'protect', :id => @page.title, :protected => 1}, :method => :post, :class => 'icon icon-lock') if !@page.protected? %>
|
||||||
|
<%= link_to_if_authorized(l(:button_unlock), {:action => 'protect', :id => @page.title, :protected => 0}, :method => :post, :class => 'icon icon-unlock') if @page.protected? %>
|
||||||
|
<%= link_to_if_authorized(l(:button_rename), {:action => 'rename', :id => @page.title}, :class => 'icon icon-move') if @annotate.content.version == @page.content.version %>
|
||||||
|
<%= link_to_if_authorized(l(:button_delete), {:action => 'destroy', :id => @page.title}, :method => :delete, :confirm => l(:text_are_you_sure), :class => 'icon icon-del') %>
|
||||||
|
<% end %>
|
||||||
|
<%= link_to_if_authorized(l(:label_history), {:action => 'history', :id => @page.title}, :class => 'icon icon-history') %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2><%= h(@page.pretty_title) %></h2>
|
<h2><%= h(@page.pretty_title) %></h2>
|
||||||
|
@ -307,6 +307,7 @@ en:
|
|||||||
field_text: Text field
|
field_text: Text field
|
||||||
field_visible: Visible
|
field_visible: Visible
|
||||||
field_warn_on_leaving_unsaved: "Warn me when leaving a page with unsaved text"
|
field_warn_on_leaving_unsaved: "Warn me when leaving a page with unsaved text"
|
||||||
|
field_custom_filter: Custom LDAP filter
|
||||||
|
|
||||||
setting_app_title: Application title
|
setting_app_title: Application title
|
||||||
setting_app_subtitle: Application subtitle
|
setting_app_subtitle: Application subtitle
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
class AddCustomFilterToAuthSources < ActiveRecord::Migration
|
||||||
|
def self.up
|
||||||
|
add_column :auth_sources, :custom_filter, :string
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.down
|
||||||
|
remove_column :auth_sources, :custom_filter
|
||||||
|
end
|
||||||
|
end
|
@ -1,55 +1,55 @@
|
|||||||
# General Apache options
|
# General Apache options
|
||||||
<IfModule mod_fastcgi.c>
|
<IfModule mod_fastcgi.c>
|
||||||
AddHandler fastcgi-script .fcgi
|
AddHandler fastcgi-script .fcgi
|
||||||
</IfModule>
|
</IfModule>
|
||||||
<IfModule mod_fcgid.c>
|
<IfModule mod_fcgid.c>
|
||||||
AddHandler fcgid-script .fcgi
|
AddHandler fcgid-script .fcgi
|
||||||
</IfModule>
|
</IfModule>
|
||||||
<IfModule mod_cgi.c>
|
<IfModule mod_cgi.c>
|
||||||
AddHandler cgi-script .cgi
|
AddHandler cgi-script .cgi
|
||||||
</IfModule>
|
</IfModule>
|
||||||
Options +FollowSymLinks +ExecCGI
|
Options +FollowSymLinks +ExecCGI
|
||||||
|
|
||||||
# If you don't want Rails to look in certain directories,
|
# If you don't want Rails to look in certain directories,
|
||||||
# use the following rewrite rules so that Apache won't rewrite certain requests
|
# use the following rewrite rules so that Apache won't rewrite certain requests
|
||||||
#
|
#
|
||||||
# Example:
|
# Example:
|
||||||
# RewriteCond %{REQUEST_URI} ^/notrails.*
|
# RewriteCond %{REQUEST_URI} ^/notrails.*
|
||||||
# RewriteRule .* - [L]
|
# RewriteRule .* - [L]
|
||||||
|
|
||||||
# Redirect all requests not available on the filesystem to Rails
|
# Redirect all requests not available on the filesystem to Rails
|
||||||
# By default the cgi dispatcher is used which is very slow
|
# By default the cgi dispatcher is used which is very slow
|
||||||
#
|
#
|
||||||
# For better performance replace the dispatcher with the fastcgi one
|
# For better performance replace the dispatcher with the fastcgi one
|
||||||
#
|
#
|
||||||
# Example:
|
# Example:
|
||||||
# RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
|
# RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
|
||||||
RewriteEngine On
|
RewriteEngine On
|
||||||
|
|
||||||
# If your Rails application is accessed via an Alias directive,
|
# If your Rails application is accessed via an Alias directive,
|
||||||
# then you MUST also set the RewriteBase in this htaccess file.
|
# then you MUST also set the RewriteBase in this htaccess file.
|
||||||
#
|
#
|
||||||
# Example:
|
# Example:
|
||||||
# Alias /myrailsapp /path/to/myrailsapp/public
|
# Alias /myrailsapp /path/to/myrailsapp/public
|
||||||
# RewriteBase /myrailsapp
|
# RewriteBase /myrailsapp
|
||||||
|
|
||||||
RewriteRule ^$ index.html [QSA]
|
RewriteRule ^$ index.html [QSA]
|
||||||
RewriteRule ^([^.]+)$ $1.html [QSA]
|
RewriteRule ^([^.]+)$ $1.html [QSA]
|
||||||
RewriteCond %{REQUEST_FILENAME} !-f
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
<IfModule mod_fastcgi.c>
|
<IfModule mod_fastcgi.c>
|
||||||
RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
|
RewriteRule ^(.*)$ dispatch.fcgi [E=X-HTTP_AUTHORIZATION:{HTTP:Authorization},QSA,L]
|
||||||
</IfModule>
|
</IfModule>
|
||||||
<IfModule mod_fcgid.c>
|
<IfModule mod_fcgid.c>
|
||||||
RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
|
RewriteRule ^(.*)$ dispatch.fcgi [E=X-HTTP_AUTHORIZATION:{HTTP:Authorization},QSA,L]
|
||||||
</IfModule>
|
</IfModule>
|
||||||
<IfModule mod_cgi.c>
|
<IfModule mod_cgi.c>
|
||||||
RewriteRule ^(.*)$ dispatch.cgi [QSA,L]
|
RewriteRule ^(.*)$ dispatch.cgi [E=X-HTTP_AUTHORIZATION:{HTTP:Authorization},QSA,L]
|
||||||
</IfModule>
|
</IfModule>
|
||||||
|
|
||||||
# In case Rails experiences terminal errors
|
# In case Rails experiences terminal errors
|
||||||
# Instead of displaying this message you can supply a file here which will be rendered instead
|
# Instead of displaying this message you can supply a file here which will be rendered instead
|
||||||
#
|
#
|
||||||
# Example:
|
# Example:
|
||||||
# ErrorDocument 500 /500.html
|
# ErrorDocument 500 /500.html
|
||||||
|
|
||||||
ErrorDocument 500 "<h2>Application error</h2>Rails application failed to start properly"
|
ErrorDocument 500 "<h2>Application error</h2>Rails application failed to start properly"
|
||||||
|
27
test/fixtures/ldap/slapd_config.ldif
vendored
Normal file
27
test/fixtures/ldap/slapd_config.ldif
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# This is a configuration for a new database to test the ldap plugin.
|
||||||
|
# It is assumed that you have a ldap server up and running. Do not
|
||||||
|
# use this file on a new openldap installation.
|
||||||
|
|
||||||
|
# Database settings
|
||||||
|
dn: olcDatabase=hdb,cn=config
|
||||||
|
objectClass: olcDatabaseConfig
|
||||||
|
objectClass: olcHdbConfig
|
||||||
|
olcDatabase: hdb
|
||||||
|
olcSuffix: dc=redmine,dc=org
|
||||||
|
# WARNING: Do not use a directory that already contains a ldap database.
|
||||||
|
# Each database has to be stored in a seperate directory. The directory
|
||||||
|
# /var/lib/ldap is the default directory on Debian.
|
||||||
|
olcDbDirectory: /var/lib/ldap/redmine
|
||||||
|
olcRootDN: cn=Manager,dc=redmine,dc=org
|
||||||
|
olcRootPW: secret
|
||||||
|
olcDbConfig: set_cachesize 0 2097152 0
|
||||||
|
olcDbConfig: set_lk_max_objects 1500
|
||||||
|
olcDbConfig: set_lk_max_locks 1500
|
||||||
|
olcDbConfig: set_lk_max_lockers 1500
|
||||||
|
olcDbIndex: objectClass eq
|
||||||
|
olcLastMod: TRUE
|
||||||
|
olcDbCheckpoint: 512 30
|
||||||
|
olcAccess: to attrs=userPassword by dn="cn=Manager,dc=redmine,dc=org" write by anonymous auth by self write by * none
|
||||||
|
olcAccess: to attrs=shadowLastChange by self write by * read
|
||||||
|
olcAccess: to dn.base="" by * read
|
||||||
|
olcAccess: to * by dn="cn=Manager,dc=redmine,dc=org" write by * read
|
42
test/fixtures/ldap/test-ldap.ldif
vendored
42
test/fixtures/ldap/test-ldap.ldif
vendored
@ -4,39 +4,11 @@ objectClass: dcObject
|
|||||||
objectClass: organization
|
objectClass: organization
|
||||||
o: redmine.org
|
o: redmine.org
|
||||||
dc: redmine
|
dc: redmine
|
||||||
structuralObjectClass: organization
|
|
||||||
entryUUID: 886f5fca-0a87-102e-8d06-67c361d9bd2d
|
|
||||||
creatorsName:
|
|
||||||
createTimestamp: 20090721211642Z
|
|
||||||
entryCSN: 20090721211642.955188Z#000000#000#000000
|
|
||||||
modifiersName:
|
|
||||||
modifyTimestamp: 20090721211642Z
|
|
||||||
|
|
||||||
dn: cn=admin,dc=redmine,dc=org
|
|
||||||
objectClass: simpleSecurityObject
|
|
||||||
objectClass: organizationalRole
|
|
||||||
cn: admin
|
|
||||||
description: LDAP administrator
|
|
||||||
userPassword:: e2NyeXB0fWlWTU9DcUt6WWxXRDI=
|
|
||||||
structuralObjectClass: organizationalRole
|
|
||||||
entryUUID: 88704e44-0a87-102e-8d07-67c361d9bd2d
|
|
||||||
creatorsName:
|
|
||||||
createTimestamp: 20090721211642Z
|
|
||||||
entryCSN: 20090721211642.961418Z#000000#000#000000
|
|
||||||
modifiersName:
|
|
||||||
modifyTimestamp: 20090721211642Z
|
|
||||||
|
|
||||||
dn: ou=Person,dc=redmine,dc=org
|
dn: ou=Person,dc=redmine,dc=org
|
||||||
ou: Person
|
ou: Person
|
||||||
objectClass: top
|
objectClass: top
|
||||||
objectClass: organizationalUnit
|
objectClass: organizationalUnit
|
||||||
structuralObjectClass: organizationalUnit
|
|
||||||
entryUUID: d39dd388-0c84-102e-82fa-dff86c63a7d6
|
|
||||||
creatorsName: cn=admin,dc=redmine,dc=org
|
|
||||||
createTimestamp: 20090724100222Z
|
|
||||||
entryCSN: 20090724100222.924226Z#000000#000#000000
|
|
||||||
modifiersName: cn=admin,dc=redmine,dc=org
|
|
||||||
modifyTimestamp: 20090724100222Z
|
|
||||||
|
|
||||||
dn: uid=example1,ou=Person,dc=redmine,dc=org
|
dn: uid=example1,ou=Person,dc=redmine,dc=org
|
||||||
objectClass: posixAccount
|
objectClass: posixAccount
|
||||||
@ -48,16 +20,9 @@ sn: One
|
|||||||
uid: example1
|
uid: example1
|
||||||
homeDirectory: /home/example1
|
homeDirectory: /home/example1
|
||||||
cn: Example One
|
cn: Example One
|
||||||
structuralObjectClass: inetOrgPerson
|
|
||||||
entryUUID: 285d304e-0c8a-102e-82fc-dff86c63a7d6
|
|
||||||
creatorsName: cn=admin,dc=redmine,dc=org
|
|
||||||
createTimestamp: 20090724104032Z
|
|
||||||
uidNumber: 0
|
uidNumber: 0
|
||||||
mail: example1@redmine.org
|
mail: example1@redmine.org
|
||||||
userPassword:: e1NIQX1mRXFOQ2NvM1lxOWg1WlVnbEQzQ1pKVDRsQnM9
|
userPassword:: e1NIQX1mRXFOQ2NvM1lxOWg1WlVnbEQzQ1pKVDRsQnM9
|
||||||
entryCSN: 20090724105945.375801Z#000000#000#000000
|
|
||||||
modifiersName: cn=admin,dc=redmine,dc=org
|
|
||||||
modifyTimestamp: 20090724105945Z
|
|
||||||
|
|
||||||
dn: uid=edavis,ou=Person,dc=redmine,dc=org
|
dn: uid=edavis,ou=Person,dc=redmine,dc=org
|
||||||
objectClass: posixAccount
|
objectClass: posixAccount
|
||||||
@ -68,15 +33,8 @@ givenName: Eric
|
|||||||
sn: Davis
|
sn: Davis
|
||||||
uid: edavis
|
uid: edavis
|
||||||
mail: edavis@littlestreamsoftware.com
|
mail: edavis@littlestreamsoftware.com
|
||||||
structuralObjectClass: inetOrgPerson
|
|
||||||
entryUUID: 9c5f0502-0c8b-102e-82fe-dff86c63a7d6
|
|
||||||
creatorsName: cn=admin,dc=redmine,dc=org
|
|
||||||
createTimestamp: 20090724105056Z
|
|
||||||
homeDirectory: /home/edavis
|
homeDirectory: /home/edavis
|
||||||
cn: Eric Davis
|
cn: Eric Davis
|
||||||
uidNumber: 0
|
uidNumber: 0
|
||||||
userPassword:: e1NIQX1mRXFOQ2NvM1lxOWg1WlVnbEQzQ1pKVDRsQnM9
|
userPassword:: e1NIQX1mRXFOQ2NvM1lxOWg1WlVnbEQzQ1pKVDRsQnM9
|
||||||
entryCSN: 20090724105937.734480Z#000000#000#000000
|
|
||||||
modifiersName: cn=admin,dc=redmine,dc=org
|
|
||||||
modifyTimestamp: 20090724105937Z
|
|
||||||
|
|
||||||
|
@ -47,6 +47,17 @@ class AccountControllerTest < ActionController::TestCase
|
|||||||
:content => /Invalid user or password/
|
:content => /Invalid user or password/
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_login
|
||||||
|
get :login
|
||||||
|
assert_template 'login'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_login_with_logged_account
|
||||||
|
@request.session[:user_id] = 2
|
||||||
|
get :login
|
||||||
|
assert_redirected_to home_url
|
||||||
|
end
|
||||||
|
|
||||||
if Object.const_defined?(:OpenID)
|
if Object.const_defined?(:OpenID)
|
||||||
|
|
||||||
def test_login_with_openid_for_existing_user
|
def test_login_with_openid_for_existing_user
|
||||||
|
@ -31,6 +31,20 @@ class AuthSourceLdapTest < ActiveSupport::TestCase
|
|||||||
assert_equal 'givenName', a.reload.attr_firstname
|
assert_equal 'givenName', a.reload.attr_firstname
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "validations" do
|
||||||
|
should "validate that custom_filter is a valid LDAP filter" do
|
||||||
|
@auth = AuthSourceLdap.new(:name => 'Validation', :host => 'localhost', :port => 389, :attr_login => 'login')
|
||||||
|
@auth.custom_filter = "(& (homeDirectory=*) (sn=O*" # Missing ((
|
||||||
|
assert @auth.invalid?
|
||||||
|
assert_equal "is invalid", @auth.errors.on(:custom_filter)
|
||||||
|
|
||||||
|
@auth.custom_filter = "(& (homeDirectory=*) (sn=O*))"
|
||||||
|
assert @auth.valid?
|
||||||
|
assert_equal nil, @auth.errors.on(:custom_filter)
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if ldap_configured?
|
if ldap_configured?
|
||||||
context '#authenticate' do
|
context '#authenticate' do
|
||||||
setup do
|
setup do
|
||||||
@ -69,6 +83,32 @@ class AuthSourceLdapTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "using a valid custom filter" do
|
||||||
|
setup do
|
||||||
|
@auth.update_attributes(:custom_filter => "(& (homeDirectory=*) (sn=O*))")
|
||||||
|
end
|
||||||
|
|
||||||
|
should "find a user who authenticates and matches the custom filter" do
|
||||||
|
assert_not_nil @auth.authenticate('example1', '123456')
|
||||||
|
end
|
||||||
|
|
||||||
|
should "be nil for users who don't match the custom filter" do
|
||||||
|
assert_nil @auth.authenticate('edavis', '123456')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "using an invalid custom filter" do
|
||||||
|
setup do
|
||||||
|
# missing )) at the end
|
||||||
|
@auth.update_attributes(:custom_filter => "(& (homeDirectory=*) (sn=O*")
|
||||||
|
end
|
||||||
|
|
||||||
|
should "skip the custom filter" do
|
||||||
|
assert_not_nil @auth.authenticate('example1', '123456')
|
||||||
|
assert_not_nil @auth.authenticate('edavis', '123456')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
puts '(Test LDAP server not configured)'
|
puts '(Test LDAP server not configured)'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user