如何使用FreeRADIUS与LinOTP 2进行双因素验证一次性密码
本手册将指导您使用LinOTP 2社区版设置RADIUS身份验证。 LinOTP是一个一次性密码后端,使您能够使用各种不同的硬件设备,软件令牌和短信进行双因素身份验证。
API
虽然Enterprise Edition附带了FreeRADIUS服务器的C模块,但是根据AGPLv3授权的Community Edition没有。 尽管如此,LinOTP提供了非常简单的WEB API,可以以多种不同的方式与LinOTP进行通信。 还有一个API进行身份验证,即要求LinOTP服务器某个用户的给定一次密码是否有效。 这是URL
https://yourServer/validate/check?user=....&pass=....
要么
https://yourServer/validate/simplecheck?user=...&pass=...
你可以在这里查看完整的API。
FreeRADIUS
简单的LinOTP API和FreeRADIUS的一些不错的模块使得通过RADIUS轻松地为OTP通过一个简单的解决方案。 您可以使用模块rlm_exec来执行外部程序,但我宁愿使用模块rlm_perl并添加有限的perl 知识库 ;-)
rlm_perl模块的文档可以在这里找到。 它有一个简单的例子,我们只需要在功能验证中进行调整。 这就是我们需要与LinOTP服务器(使用上述URL)进行交谈的依据,并根据LinOTP反馈进行回复。
解决方案
所以pre-beta中的perl模块将会如下所示:
# # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA # # Copyright 2002 The FreeRADIUS server project # Copyright 2002 Boian Jordanov <bjordanov@orbitel.bg> # Copyright 2011 linotp project <linotp@lsexperts.de> # # Based on the Example code for use with rlm_perl # # =head1 NAME freeradius_perl - Perl module for use with FreeRADIUS rlm_perl, to authenticate against LinOTP http://www.linotp.org =head1 SYNOPSIS use with freeradius: Configure rlm_perl to work with LinOTP: in /etc/freeradius/users set: DEFAULT Auth-type := perl in /etc/freeradius/modules/perl point perl { module = to this file in /etc/freeradius/sites-enabled/<yoursite> set authenticate{ perl [....] =head1 DESCRIPTION This module enables freeradius to authenticate using LinOTP. TODO: * checking of server certificate =head2 Methods * authenticate =head1 AUTHOR Cornelius Koelbel (cornelius.koelbel@lsexperts.de) =head1 COPYRIGHT Copyright 2011 This library is free software; you can redistribute it under the GPLv2. =head1 SEE ALSO perl(1). =cut use strict; use LWP 5.64; # use ... # This is very important ! Without this script will not get the filled hashesh from main. use vars qw(%RAD_REQUEST %RAD_REPLY %RAD_CHECK $URL); use Data::Dumper; $URL = "https://localhost/validate/simplecheck"; # This is hash wich hold original request from radius #my %RAD_REQUEST; # In this hash you add values that will be returned to NAS. #my %RAD_REPLY; #This is for check items #my %RAD_CHECK; # # This the remapping of return values # use constant RLM_MODULE_REJECT=> 0;# /* immediately reject the request */ use constant RLM_MODULE_FAIL=> 1;# /* module failed, don't reply */ use constant RLM_MODULE_OK=> 2;# /* the module is OK, continue */ use constant RLM_MODULE_HANDLED=> 3;# /* the module handled the request, so stop. */ use constant RLM_MODULE_INVALID=> 4;# /* the module considers the request invalid. */ use constant RLM_MODULE_USERLOCK=> 5;# /* reject the request (user is locked out) */ use constant RLM_MODULE_NOTFOUND=> 6;# /* user not found */ use constant RLM_MODULE_NOOP=> 7;# /* module succeeded without doing anything */ use constant RLM_MODULE_UPDATED=> 8;# /* OK (pairs modified) */ use constant RLM_MODULE_NUMCODES=> 9;# /* How many return codes there are */ # Function to handle authorize sub authorize { # For debugging purposes only # &log_request_attributes; # Here's where your authorization code comes # You can call another function from here: &test_call; return RLM_MODULE_OK; } # Function to handle authenticate sub authenticate { # For debugging purposes only # &log_request_attributes; my $ua = LWP::UserAgent->new(); my $req = HTTP::Request->new(GET => $URL . "?user=" . $RAD_REQUEST{'User-Name'} . "&pass=" . $RAD_REQUEST{'User-Password'} ); my $response = $ua->request( $req ); die "Error at $URL\n ", $response->status_line, "\n Aborting" unless $response->is_success; if($response->content =~ m/:\-\)/i) { return RLM_MODULE_OK; } else { $RAD_REPLY{'Reply-Message'} = "LinOTP server denied access!"; return RLM_MODULE_REJECT; } } # Function to handle preacct sub preacct { # For debugging purposes only # &log_request_attributes; return RLM_MODULE_OK; } # Function to handle accounting sub accounting { # For debugging purposes only # &log_request_attributes; # You can call another subroutine from here &test_call; return RLM_MODULE_OK; } # Function to handle checksimul sub checksimul { # For debugging purposes only # &log_request_attributes; return RLM_MODULE_OK; } # Function to handle pre_proxy sub pre_proxy { # For debugging purposes only # &log_request_attributes; return RLM_MODULE_OK; } # Function to handle post_proxy sub post_proxy { # For debugging purposes only # &log_request_attributes; return RLM_MODULE_OK; } # Function to handle post_auth sub post_auth { # For debugging purposes only # &log_request_attributes; return RLM_MODULE_OK; } # Function to handle xlat sub xlat { # For debugging purposes only # &log_request_attributes; # Loads some external perl and evaluate it my ($filename,$a,$b,$c,$d) = @_; &radiusd::radlog(1, "From xlat $filename "); &radiusd::radlog(1,"From xlat $a $b $c $d "); local *FH; open FH, $filename or die "open '$filename' $!"; local($/) = undef; my $sub = <FH>; close FH; my $eval = qq{ sub handler{ $sub;} }; eval $eval; eval {main->handler;}; } # Function to handle detach sub detach { # For debugging purposes only # &log_request_attributes; # Do some logging. &radiusd::radlog(0,"rlm_perl::Detaching. Reloading. Done."); } # # Some functions that can be called from other functions # sub test_call { # Some code goes here } sub log_request_attributes { # This shouldn't be done in production environments! # This is only meant for debugging! for (keys %RAD_REQUEST) { &radiusd::radlog(1, "RAD_REQUEST: $_ = $RAD_REQUEST{$_}"); } } 1;
您将需要配置一些FreeRADIUS文件,并且还调整perl模块本身的$ URL。
结论
请注意,这是一个简单而简单的方式来获取RADIUS运行。 有一些事情丢失,错误处理日志记录会很好,冗余如何,SSL证书没有被检查!
然而,它显示使用简单的API将LinOTP集成到您的环境中是多么容易。