Commit 6a58d3eb authored by wurblzap%gmail.com's avatar wurblzap%gmail.com

Bug 380187 – Bugzilla should support RADIUS authentication.

Patch by Marc Schumann <wurblzap@gmail.com>; r=mkanat, a=mkanat
parent 037a33e6
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is the Bugzilla Bug Tracking System.
#
# The Initial Developer of the Original Code is Marc Schumann.
# Portions created by Marc Schumann are Copyright (c) 2007 Marc Schumann.
# All rights reserved.
#
# Contributor(s): Marc Schumann <wurblzap@gmail.com>
package Bugzilla::Auth::Verify::RADIUS;
use strict;
use base qw(Bugzilla::Auth::Verify);
use Bugzilla::Constants;
use Bugzilla::Error;
use Bugzilla::Util;
use Authen::Radius;
use constant admin_can_create_account => 0;
use constant user_can_create_account => 0;
sub check_credentials {
my ($self, $params) = @_;
my $dbh = Bugzilla->dbh;
my $address_suffix = Bugzilla->params->{'RADIUS_email_suffix'};
my $username = $params->{username};
# If we're using RADIUS_email_suffix, we may need to cut it off from
# the login name.
if ($address_suffix) {
$username =~ s/\Q$address_suffix\E$//i;
}
# Create RADIUS object.
my $radius =
new Authen::Radius(Host => Bugzilla->params->{'RADIUS_server'},
Secret => Bugzilla->params->{'RADIUS_secret'})
|| return { failure => AUTH_ERROR, error => 'radius_preparation_error',
details => {errstr => Authen::Radius::strerror() } };
# Check the password.
$radius->check_pwd($username, $params->{password},
Bugzilla->params->{'RADIUS_NAS_IP'} || undef)
|| return { failure => AUTH_LOGINFAILED };
# Build the user account's e-mail address.
$params->{bz_username} = $username . $address_suffix;
return $params;
}
1;
...@@ -76,8 +76,8 @@ sub get_param_list { ...@@ -76,8 +76,8 @@ sub get_param_list {
{ {
name => 'user_verify_class', name => 'user_verify_class',
type => 's', type => 'o',
choices => [ 'DB', 'LDAP', 'DB,LDAP', 'LDAP,DB' ], choices => [ 'DB', 'RADIUS', 'LDAP' ],
default => 'DB', default => 'DB',
checker => \&check_user_verify_class checker => \&check_user_verify_class
}, },
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
# Joseph Heenan <joseph@heenan.me.uk> # Joseph Heenan <joseph@heenan.me.uk>
# Erik Stambaugh <erik@dasbistro.com> # Erik Stambaugh <erik@dasbistro.com>
# Frédéric Buclin <LpSolit@gmail.com> # Frédéric Buclin <LpSolit@gmail.com>
# Marc Schumann <wurblzap@gmail.com>
# #
package Bugzilla::Config::Common; package Bugzilla::Config::Common;
...@@ -64,8 +65,8 @@ sub check_multi { ...@@ -64,8 +65,8 @@ sub check_multi {
return ""; return "";
} }
elsif ($param->{'type'} eq "m") { elsif ($param->{'type'} eq 'm' || $param->{'type'} eq 'o') {
foreach my $chkParam (@$value) { foreach my $chkParam (split(',', $value)) {
unless (scalar(grep {$_ eq $chkParam} (@{$param->{'choices'}}))) { unless (scalar(grep {$_ eq $chkParam} (@{$param->{'choices'}}))) {
return "Invalid choice '$chkParam' for multi-select list param '$param->{'name'}'"; return "Invalid choice '$chkParam' for multi-select list param '$param->{'name'}'";
} }
...@@ -268,18 +269,27 @@ sub check_user_verify_class { ...@@ -268,18 +269,27 @@ sub check_user_verify_class {
# So don't do that. # So don't do that.
my ($list, $entry) = @_; my ($list, $entry) = @_;
$list || return 'You need to specify at least one authentication mechanism';
for my $class (split /,\s*/, $list) { for my $class (split /,\s*/, $list) {
my $res = check_multi($class, $entry); my $res = check_multi($class, $entry);
return $res if $res; return $res if $res;
if ($class eq 'DB') { if ($class eq 'DB') {
# No params # No params
} elsif ($class eq 'LDAP') { }
elsif ($class eq 'RADIUS') {
eval "require Authen::Radius";
return "Error requiring Authen::Radius: '$@'" if $@;
return "RADIUS servername (RADIUS_server) is missing" unless Bugzilla->params->{"RADIUS_server"};
return "RADIUS_secret is empty" unless Bugzilla->params->{"RADIUS_secret"};
}
elsif ($class eq 'LDAP') {
eval "require Net::LDAP"; eval "require Net::LDAP";
return "Error requiring Net::LDAP: '$@'" if $@; return "Error requiring Net::LDAP: '$@'" if $@;
return "LDAP servername is missing" unless Bugzilla->params->{"LDAPserver"}; return "LDAP servername (LDAPserver) is missing" unless Bugzilla->params->{"LDAPserver"};
return "LDAPBaseDN is empty" unless Bugzilla->params->{"LDAPBaseDN"}; return "LDAPBaseDN is empty" unless Bugzilla->params->{"LDAPBaseDN"};
} else { }
return "Unknown user_verify_class '$class' in check_user_verify_class"; else {
return "Unknown user_verify_class '$class' in check_user_verify_class";
} }
} }
return ""; return "";
...@@ -363,9 +373,8 @@ sub check_timezone { ...@@ -363,9 +373,8 @@ sub check_timezone {
# b -- A boolean value (either 1 or 0) # b -- A boolean value (either 1 or 0)
# m -- A list of values, with many selectable (shows up as a select box) # m -- A list of values, with many selectable (shows up as a select box)
# To specify the list of values, make the 'choices' key be an array # To specify the list of values, make the 'choices' key be an array
# reference of the valid choices. The 'default' key should be an array # reference of the valid choices. The 'default' key should be a string
# reference for the list of selected values (which must appear in the # with a list of selected values (as a comma-separated list), i.e.:
# first anonymous array), i.e.:
# { # {
# name => 'multiselect', # name => 'multiselect',
# desc => 'A list of options, choose many', # desc => 'A list of options, choose many',
...@@ -381,6 +390,11 @@ sub check_timezone { ...@@ -381,6 +390,11 @@ sub check_timezone {
# &check_multi should always be used as the param verification function # &check_multi should always be used as the param verification function
# for list (single and multiple) parameter types. # for list (single and multiple) parameter types.
# #
# o -- A list of values, orderable, and with many selectable (shows up as a
# JavaScript-enhanced select box if JavaScript is enabled, and a text
# entry field if not)
# Set up in the same way as type m.
#
# s -- A list of values, with one selectable (shows up as a select box) # s -- A list of values, with one selectable (shows up as a select box)
# To specify the list of values, make the 'choices' key be an array # To specify the list of values, make the 'choices' key be an array
# reference of the valid choices. The 'default' key should be one of # reference of the valid choices. The 'default' key should be one of
...@@ -422,7 +436,7 @@ All parameter checking functions are called with two parameters: ...@@ -422,7 +436,7 @@ All parameter checking functions are called with two parameters:
=item C<check_multi> =item C<check_multi>
Checks that a multi-valued parameter (ie type C<s> or type C<m>) satisfies Checks that a multi-valued parameter (ie types C<s>, C<o> or C<m>) satisfies
its contraints. its contraints.
=item C<check_numeric> =item C<check_numeric>
......
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is the Bugzilla Bug Tracking System.
#
# The Initial Developer of the Original Code is Marc Schumann.
# Portions created by Marc Schumann are Copyright (c) 2007 Marc Schumann.
# All rights reserved.
#
# Contributor(s): Marc Schumann <wurblzap@gmail.com>
#
package Bugzilla::Config::RADIUS;
use strict;
use Bugzilla::Config::Common;
$Bugzilla::Config::RADIUS::sortkey = "09";
sub get_param_list {
my $class = shift;
my @param_list = (
{
name => 'RADIUS_server',
type => 't',
default => ''
},
{
name => 'RADIUS_secret',
type => 't',
default => ''
},
{
name => 'RADIUS_NAS_IP',
type => 't',
default => ''
},
{
name => 'RADIUS_email_suffix',
type => 't',
default => ''
},
);
return @param_list;
}
1;
...@@ -170,6 +170,12 @@ sub OPTIONAL_MODULES { ...@@ -170,6 +170,12 @@ sub OPTIONAL_MODULES {
feature => 'LDAP Authentication' feature => 'LDAP Authentication'
}, },
{ {
package => 'RadiusPerl',
module => 'Authen::Radius',
version => 0,
feature => 'RADIUS Authentication'
},
{
package => 'SOAP-Lite', package => 'SOAP-Lite',
module => 'SOAP::Lite', module => 'SOAP::Lite',
version => 0, version => 0,
......
<!-- <!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"> --> <!-- <!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"> -->
<!-- $Id: installation.xml,v 1.139 2007/07/24 18:22:02 timeless%mozdev.org Exp $ --> <!-- $Id: installation.xml,v 1.140 2007/08/02 22:38:43 wurblzap%gmail.com Exp $ -->
<chapter id="installing-bugzilla"> <chapter id="installing-bugzilla">
<title>Installing Bugzilla</title> <title>Installing Bugzilla</title>
...@@ -420,6 +420,13 @@ ...@@ -420,6 +420,13 @@
<listitem> <listitem>
<para> <para>
Authen::Radius
(&min-authen-radius-ver;) for RADIUS Authentication
</para>
</listitem>
<listitem>
<para>
<link linkend="install-modules-soap-lite">SOAP::Lite</link> <link linkend="install-modules-soap-lite">SOAP::Lite</link>
(&min-soap-lite-ver;) for the web service interface (&min-soap-lite-ver;) for the web service interface
</para> </para>
...@@ -1506,6 +1513,72 @@ c:\perl\bin\perl.exe -xc:\bugzilla -wT "%s" %s ...@@ -1506,6 +1513,72 @@ c:\perl\bin\perl.exe -xc:\bugzilla -wT "%s" %s
</section> </section>
<section id="bzradius">
<title>RADIUS Authentication</title>
<para>RADIUS authentication is a module for Bugzilla's plugin
authentication architecture.
Most caveats that apply to LDAP authentication apply to RADIUS
authentication as well.
</para>
<para>Parameters required to use RADIUS Authentication:</para>
<variablelist>
<varlistentry id="param-user_verify_class">
<term>user_verify_class</term>
<listitem>
<para>If you want to list <quote>RADIUS</quote> here,
make sure to have set up the other parameters listed below.
Unless you have other (working) authentication methods listed as
well, you may otherwise not be able to log back in to Bugzilla once
you log out.
If this happens to you, you will need to manually edit
<filename>data/params</filename> and set user_verify_class to
<quote>DB</quote>.
</para>
</listitem>
</varlistentry>
<varlistentry id="param-RADIUS_server">
<term>RADIUS_server</term>
<listitem>
<para>This parameter should be set to the name (and optionally the
port) of your RADIUS server.
</para>
</listitem>
</varlistentry>
<varlistentry id="param-RADIUS_secret">
<term>RADIUS_secret</term>
<listitem>
<para>This parameter should be set to the RADIUS server's secret.
</para>
</listitem>
</varlistentry>
<varlistentry id="param-RADIUS_email_suffix">
<term>RADIUS_email_suffix</term>
<listitem>
<para>Bugzilla needs an e-mail address for each user account.
Therefore, it needs to determine the e-mail address corresponding
to a RADIUS user.
Bugzilla offers only a simple way to do this: it can concatenate
a suffix to the RADIUS user name to convert it into an e-mail
address.
You can specify this suffix in the RADIUS_email_suffix parameter.
</para>
<para>If this simple solution does not work for you, you'll
probably need to modify
<filename>Bugzilla/Auth/Verify/RADIUS.pm</filename> to match your
requirements.
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section id="bzldap"> <section id="bzldap">
<title>LDAP Authentication</title> <title>LDAP Authentication</title>
...@@ -1553,12 +1626,12 @@ c:\perl\bin\perl.exe -xc:\bugzilla -wT "%s" %s ...@@ -1553,12 +1626,12 @@ c:\perl\bin\perl.exe -xc:\bugzilla -wT "%s" %s
<varlistentry id="param-user_verify_class"> <varlistentry id="param-user_verify_class">
<term>user_verify_class</term> <term>user_verify_class</term>
<listitem> <listitem>
<para>This parameter should be set to <quote>LDAP</quote> <para>If you want to list <quote>LDAP</quote> here,
<emphasis>only</emphasis> if you will be using an LDAP directory make sure to have set up the other parameters listed below.
for authentication. If you set this param to <quote>LDAP</quote> but Unless you have other (working) authentication methods listed as
fail to set up the other parameters listed below you will not be well, you may otherwise not be able to log back in to Bugzilla once
able to log back in to Bugzilla one you log out. If this happens you log out.
to you, you will need to manually edit If this happens to you, you will need to manually edit
<filename>data/params</filename> and set user_verify_class to <filename>data/params</filename> and set user_verify_class to
<quote>DB</quote>. <quote>DB</quote>.
</para> </para>
......
/* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the Bugzilla Bug Tracking System.
*
* The Initial Developer of the Original Code is Marc Schumann.
* Portions created by Marc Schumann are Copyright (c) 2007 Marc Schumann.
* All rights reserved.
*
* Contributor(s): Marc Schumann <wurblzap@gmail.com>
*/
function sortedList_moveItem(paramName, direction, separator) {
var select = document.getElementById('select_' + paramName);
var inputField = document.getElementById('input_' + paramName);
var currentIndex = select.selectedIndex;
var newIndex = currentIndex + direction;
var optionCurrentIndex;
var optionNewIndex;
/* Return if no selection */
if (currentIndex < 0) return;
/* Return if trying to move upward out of list */
if (newIndex < 0) return;
/* Return if trying to move downward out of list */
if (newIndex >= select.length) return;
/* Move selection */
optionNewIndex = select.options[newIndex];
optionCurrentIndex = select.options[currentIndex];
/* Because some browsers don't accept the same option object twice in a
* selection list, we need to put a blank option here first */
select.options[newIndex] = new Option();
select.options[currentIndex] = optionNewIndex;
select.options[newIndex] = optionCurrentIndex;
select.selectedIndex = newIndex;
populateInputField(select, inputField, separator);
}
function populateInputField(select, inputField, separator) {
var i;
var stringRepresentation = '';
for (i = 0; i < select.length; i++) {
if (select.options[i].value == separator) {
break;
}
if (stringRepresentation != '') {
stringRepresentation += ',';
}
stringRepresentation += select.options[i].value;
}
inputField.value = stringRepresentation;
}
...@@ -48,6 +48,12 @@ dd { ...@@ -48,6 +48,12 @@ dd {
margin-bottom: 1.5em; margin-bottom: 1.5em;
} }
.sortlist_separator {
font-weight: bold;
font-size: 80%;
background-color: #dddddd;
}
.contribute { .contribute {
border: 1px dotted black; border: 1px dotted black;
padding: .5em; padding: .5em;
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
# #
# Contributor(s): Dave Miller <justdave@bugzilla.org> # Contributor(s): Dave Miller <justdave@bugzilla.org>
# Frédéric Buclin <LpSolit@gmail.com> # Frédéric Buclin <LpSolit@gmail.com>
# Marc Schumann <wurblzap@gmail.com>
#%] #%]
[% [%
title = "User Authentication" title = "User Authentication"
...@@ -67,12 +68,23 @@ ...@@ -67,12 +68,23 @@
${terms.Bugzilla}'s built-in authentication. This is the most common ${terms.Bugzilla}'s built-in authentication. This is the most common
choice. choice.
</dd> </dd>
<dt>RADIUS</dt>
<dd>
RADIUS authentication using a RADIUS server.
This method is experimental; please see the
$terms.Bugzilla documentation for more information.
Using this method requires
<a href=\"?section=radius\">additional
parameters</a> to be set.
</dd>
<dt>LDAP</dt> <dt>LDAP</dt>
<dd> <dd>
LDAP authentication using an LDAP server. This method is LDAP authentication using an LDAP server.
experimental; please see the $terms.Bugzilla documentation for more This method is experimental; please see the
information. Using this method requires additional parameters $terms.Bugzilla documentation for more information.
to be set above. Using this method requires
<a href=\"?section=ldap\">additional
parameters</a> to be set.
</dd> </dd>
</dl>", </dl>",
...@@ -121,4 +133,4 @@ ...@@ -121,4 +133,4 @@
"to be created. If this parameter is left blank, no users " _ "to be created. If this parameter is left blank, no users " _
"will be permitted to create their own accounts and all accounts " _ "will be permitted to create their own accounts and all accounts " _
"will have to be created by an administrator." } "will have to be created by an administrator." }
%] %]
\ No newline at end of file
...@@ -17,11 +17,14 @@ ...@@ -17,11 +17,14 @@
# Rights Reserved. # Rights Reserved.
# #
# Contributor(s): Frédéric Buclin <LpSolit@gmail.com> # Contributor(s): Frédéric Buclin <LpSolit@gmail.com>
# Marc Schumann <wurblzap@gmail.com>
#%] #%]
[%# INTERFACE: [%# INTERFACE:
# panel: hash representing the current panel. # panel: hash representing the current panel.
#%] #%]
[% sortlist_separator = '---' %]
<dl> <dl>
[% FOREACH param = panel.param_list %] [% FOREACH param = panel.param_list %]
<dt><a name="[% param.name FILTER html %]">[% param.name FILTER html %]</a></dt> <dt><a name="[% param.name FILTER html %]">[% param.name FILTER html %]</a></dt>
...@@ -53,6 +56,57 @@ ...@@ -53,6 +56,57 @@
</option> </option>
[% END %] [% END %]
</select> </select>
[% ELSIF param.type == "o" %]
<script type="text/javascript"><!--
document.write("<span style=\"display: none\">");
// -->
</script>
<input id="input_[% param.name FILTER html %]" size="80"
name="[% param.name FILTER html %]"
value="[% Param(param.name) FILTER html %]"><br>
<script type="text/javascript"><!--
document.write("<\/span>");
// -->
</script>
[% boxSize = 7 %]
[% boxSize = 3 + param.choices.size IF param.choices.size < 7 %]
[% plist = Param(param.name).split(',') %]
<script type="text/javascript"><!--
document.write(
'<table>' +
' <tr>' +
' <td rowspan="2">' +
' <select id="select_[% param.name FILTER html %]"' +
' size="[% boxSize FILTER html %]"' +
' name="select_[% param.name FILTER html %]">' +
[% FOREACH item = plist %]
' <option value="[% item FILTER html %]">[% item FILTER html %]<\/option>' +
[% END %]
' <option class="sortlist_separator"' +
' disabled="disabled"' +
' value="[% sortlist_separator %]">active&uarr;&nbsp;&darr;inactive<\/option>' +
[% FOREACH item = param.choices %]
[% IF lsearch(plist, item) == -1 %]
' <option value="[% item FILTER html %]">[% item FILTER html %]<\/option>' +
[% END %]
[% END %]
' <\/select>' +
' <\/td>' +
' <td style="vertical-align: bottom">' +
' <button type="button"' +
' onClick="sortedList_moveItem(\'[% param.name FILTER html %]\', -1, \'[% sortlist_separator %]\');">&uarr;<\/button>' +
' <\/td>' +
' <\/tr>' +
' <tr>' +
' <td style="vertical-align: top">' +
' <button type="button"' +
' onClick="sortedList_moveItem(\'[% param.name FILTER html %]\', +1, \'[% sortlist_separator %]\');">&darr;<\/button>' +
' <\/td>' +
' <\/tr>' +
'<\/table>');
// -->
</script>
[% ELSIF param.type == "s" %] [% ELSIF param.type == "s" %]
<select name="[% param.name FILTER html %]"> <select name="[% param.name FILTER html %]">
[% FOREACH item = param.choices %] [% FOREACH item = param.choices %]
......
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
title = title title = title
message = message message = message
style_urls = ['skins/standard/params.css'] style_urls = ['skins/standard/params.css']
javascript_urls = ['js/params.js']
%] %]
<table border="0" width="100%"> <table border="0" width="100%">
......
[%# 1.0@bugzilla.org %]
[%# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is the Bugzilla Bug Tracking System.
#
# The Initial Developer of the Original Code is Marc Schumann.
# Portions created by Marc Schumann are Copyright (c) 2007 Marc Schumann.
# All rights reserved.
#
# Contributor(s): Marc Schumann <wurblzap@gmail.com>
#%]
[%
title = "RADIUS"
desc = "Configure this first before choosing RADIUS as an authentication method"
%]
[% param_descs = {
RADIUS_server => "The name (and optionally port) of your RADIUS server " _
"(e.g. <code>radius.company.com</code>, or " _
"<code>radius.company.com:portnum</code>).<br>" _
"Required only if " _
"<a href=\"?section=auth#user_verify_class\">the " _
"<code>user_verify_class</code> parameter</a> contains " _
"<code>RADIUS</code>.",
RADIUS_secret => "Your RADIUS server's secret.<br>" _
"Required only if " _
"<a href=\"?section=auth#user_verify_class\">the " _
"<code>user_verify_class</code> parameter</a> contains " _
"<code>RADIUS</code>.",
RADIUS_NAS_IP => "The NAS-IP-Address attribute to be used when exchanging " _
"data with your RADIUS server. " _
"If unspecified, <code>127.0.0.1</code> will be used.<br>" _
"Useful only if " _
"<a href=\"?section=auth#user_verify_class\">the " _
"<code>user_verify_class</code> parameter</a> " _
"contains <code>RADIUS</code>.",
RADIUS_email_suffix => "Suffix to append to a RADIUS user name to form an " _
"e-mail address.<br>" _
"Useful only if " _
"<a href=\"?section=auth#user_verify_class\">the " _
"<code>user_verify_class</code> parameter</a> " _
"contains <code>RADIUS</code>.",
}
%]
...@@ -463,6 +463,10 @@ ...@@ -463,6 +463,10 @@
'link_uri' 'link_uri'
], ],
'admin/params/common.html.tmpl' => [
'sortlist_separator',
],
'admin/products/groupcontrol/confirm-edit.html.tmpl' => [ 'admin/products/groupcontrol/confirm-edit.html.tmpl' => [
'group.count', 'group.count',
], ],
......
...@@ -337,6 +337,9 @@ ...@@ -337,6 +337,9 @@
outside the package. This function may only be called from outside the package. This function may only be called from
a subclass of <code>[% superclass FILTER html %]</code>. a subclass of <code>[% superclass FILTER html %]</code>.
[% ELSIF error == "radius_preparation_error" %]
An error occurred while preparing for a RADIUS authentication request:
<code>[% errstr FILTER html %]</code>.
[% ELSIF error == "unknown_comparison_type" %] [% ELSIF error == "unknown_comparison_type" %]
Specified comparison type is not supported. Specified comparison type is not supported.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment