View Issue Details

IDProjectCategoryView StatusLast Update
0003887mantisbtauthenticationpublic2013-06-10 21:12
Reporterjcs Assigned To 
PrioritynormalSeverityfeatureReproducibilityN/A
Status acknowledgedResolutionopen 
Summary0003887: radius authentcation support [patch]
Description

new core/radius_api.php file and patches to existing files (against 0.18.3) to support a $g_login_method of "RADIUS"

Additional Information

radius code is under a bsd license.

i tried to follow the mantis coding style as closely as possible.

TagsNo tags attached.
Attached Files
mantis-0.18.3-radius.diff (10,945 bytes)   
--- /dev/null	Mon May 24 21:34:30 2004
+++ core/radius_api.php	Mon May 24 21:34:27 2004
@@ -0,0 +1,236 @@
+<?php
+	# $DLS: radius_api.php,v 1.6 2004/05/25 02:33:50 jcs Exp $
+	#
+	# Copyright (c) 2004, DLS Internet Services
+	# Written by Joshua Stein <jcs@eng.dls.net>
+	#
+	# Includes code from Edwin Groothuis <edwin@mavetju.org>
+	# Copyright 2000, 2001, 2002 by Edwin Groothuis. All rights reserved.
+	#
+	# Redistribution and use in source and binary forms, with or without
+	# modification, are permitted provided that the following conditions
+	# are met:
+	# 1. Redistributions of source code must retain the above copyright
+	#    notice, this list of conditions and the following disclaimer.
+	# 2. Redistributions in binary form must reproduce the above copyright
+	#    notice, this list of conditions and the following disclaimer in the
+	#    documentation and/or other materials provided with the distribution.
+	# 3. All advertising materials mentioning features or use of this software
+	#    must display the following acknowledgement:
+	#    This product includes software developed by Edwin Groothuis.
+	# 4. Neither the name of Edwin Groothuis may be used to endorse or
+	#    promote products derived from this software without specific
+	#    prior written permission.
+	# 
+	# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+	# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+	# DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+	# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+	# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+	# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+	# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+	# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+	# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+	# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+	# --------------------------------------------------------
+	# $Id: radius_api.php,v 1.6 2004/05/25 02:33:50 jcs Exp $
+	# --------------------------------------------------------
+
+	###########################################################################
+	# RADIUS Authentication API
+	###########################################################################
+
+	# --------------------
+	# Wrapper for radius_doauth
+	function radius_authenticate( $p_user_id = '', $p_password = '') {
+		$t_username = user_get_field( $p_user_id, 'username' );
+
+		$t_server = config_get( 'radius_server' );
+		$t_port = config_get( 'radius_port' );
+		$t_secret = config_get( 'radius_secret' );
+		$t_timeout = config_get( 'radius_timeout' );
+
+		$t_retval = radius_doauth( $t_username, $p_password, $t_server, $t_port,
+			$t_secret, $t_timeout );
+
+		# 2 == Access-Accept
+		# 3 == Access-Reject
+		if ( $t_retval == 2 )
+			return true;
+		else
+			return false;
+	}
+
+	# --------------------
+	# Actual socket and verification routines
+	function radius_doauth( $p_username, $p_password, $p_server, $p_port = 1812,
+	$p_secret, $p_timeout = 3 ) {
+		$t_encpassword = "";
+
+		# store each octet of our server's ip in an array, to use as the nas
+		# client
+		$t_me = explode( ".", $_SERVER["SERVER_ADDR"] );
+
+		# copy
+		$t_temppassword = $p_password;
+
+		# create socket
+		$t_radip = gethostbyname( $p_server );
+		$t_socket = socket_create( AF_INET, SOCK_DGRAM, SOL_UDP );
+		$t_retval = socket_connect( $t_socket, $t_radip, $p_port );
+
+		# generate 16 bytes of randomness
+		$t_authenticator = pack( "CCCCCCCCCCCCCCCC",
+			1 + rand() % 255, 1 + rand() % 255, 1 + rand() % 255,
+			1 + rand() % 255, 1 + rand() % 255, 1 + rand() % 255,
+			1 + rand() % 255, 1 + rand() % 255, 1 + rand() % 255,
+			1 + rand() % 255, 1 + rand() % 255, 1 + rand() % 255,
+			1 + rand() % 255, 1 + rand() % 255, 1 + rand() % 255,
+			1 + rand() % 255 ); 
+
+		# pad password a multiple of 16 bytes
+		if ( ( strlen( $t_temppassword ) % 16 ) != 0 )
+			for ( $x = 16; $x > ( strlen( $t_temppassword ) % 16 ); $x-- )
+				$t_temppassword .= "\0";
+
+		# cut up into 16-byte pieces, hash each one
+		for ( $x = 0; $x <= ( intval( strlen( $t_temppassword ) - 1) / 16);
+		$x++ ) {
+			$t_piece = substr( $t_temppassword, ( $x * 16 ), 16 );
+
+			if ( strlen( $t_encpassword ) )
+				# instead of using the authenticator, we use 16 octets from the
+				# first xor
+				$t_encpassword .= radius_md5hash( $t_piece, $p_secret,
+					substr( $t_encpassword, ( $x - 1 ) * 16, 16 ) );
+			else
+				$t_encpassword .= radius_md5hash( $t_piece, $p_secret,
+					$t_authenticator );
+		}
+
+		# length of entire packet, needed in the packet itself
+		$t_slen = 4 + 16 + 6 + ( 2 + strlen( $p_username ) ) +
+			( 2 + strlen( $t_encpassword ) ) + 6 + 6;
+
+		# unique request
+		$t_reqid = rand() % 256;
+
+		# assemble the packet
+		$t_payload = pack(
+			"CCCC" .														# code, ident, len 
+			"a*" .														# authenticator 
+			"CCCCCC" .													# service type 
+			"CCa*" .														# 1: username 
+			"CCa*" .														# 2: password 
+			"CCCCCC" .													# 4: nas ip 
+			"CCCCCC",													# 5: nas port 
+
+			1, $t_reqid, $t_slen / 256, $t_slen % 256,		# access-request 
+			$t_authenticator,											# authenticator 
+			6, 6, 0, 0, 0, 1,											# service-type 
+			1, 2 + strlen( $p_username ), $p_username,		# 1: username 
+			2, 2 + strlen( $t_encpassword ), $t_encpassword,# 2: password 
+			4, 6, $t_me[0], $t_me[1], $t_me[2], $t_me[3],	# 4: our IP 
+			5, 6, 0, 0, 0, 0 );										# 5: nas port 
+	
+		/* send it */
+		socket_write( $t_socket, $t_payload, $t_slen );
+
+		if ( function_exists( "socket_select" ) ) {
+			# timeout after a specified amount of seconds
+			$t_read = array( $t_socket );
+			if ( !socket_select( $t_read, $t_junk = NULL, $t_junk = NULL,
+			$p_timeout ) ) {
+				error_log( "RADIUS server " . $p_server . " did not respond "
+					. "within " . $timeout . " second"
+					. ( $timeout == 1 ? "" : "s" ) );
+
+				return -1;
+			}
+		}
+
+		# get our response and clean up
+		$t_readdata = @socket_read( $t_socket, 4096 );
+		socket_close( $t_socket );
+
+		if ( $t_readdata ) {
+			# 0, 1 - code
+			# 1, 1 - identifier
+			# 2, 2 - length
+			# 4, 16 - authenticator
+			# 20, ? - variable length attributes
+
+			# pull out the identifier and make sure this is our request
+			if ( ord( substr( $t_readdata, 1, 1 ) ) != $t_reqid ) {
+				error_log( "Got RADIUS reply from " . $p_server . " for a request "
+					. "that wasn't ours" );
+
+				return -1;
+			}
+
+			# pull out the authenticator
+			$t_checkauth = substr( $t_readdata, 4, 16 );
+
+			# encode the returned packet with our original authenticator and secret
+			$t_checkver = radius_md5bin( substr( $t_readdata, 0, 4)
+				. $t_authenticator . substr( $t_readdata, 20,
+				strlen( $t_readdata ) - 20 ) . $p_secret );
+	
+			if ($t_checkver != $t_checkauth) {
+				# packet authentication failed, something broke along the way
+				error_log( "RADIUS authentication packet from " . $p_server
+					. " for user " . $p_username . " fails verification" );
+
+				return -1;
+			}
+
+			# we have a successful return packet, return the code from the server
+			# 2 == Access-Accept, 3 == Access-Reject
+			return ord( substr( $t_readdata, 0, 1 ) );
+		} else {
+			# no response
+			error_log( "RADIUS server " . $p_server . " responded with no "
+				. "answer" );
+
+			return -1;
+		}
+	}
+
+	# --------------------
+	# Hashing routine
+	function radius_md5hash( $p_password, $p_key, $p_random ) {
+		$t_keyrandom = $p_key . $p_random;
+		$t_checksum = md5( $t_keyrandom );
+
+		$t_output = "";
+
+		for ( $x = 0; $x <= 15; $x++ ) {
+			if ( ( 2 * $x ) > strlen( $t_checksum ) )
+				$t_m = 0;
+			else
+				$t_m = hexdec( substr( $t_checksum, ( 2 * $x ), 2 ) );
+
+			if ($x > strlen( $p_password ) )
+				$t_p = 0;
+			else
+				$t_p = ord( substr( $p_password, $x, 1 ) );
+
+			$t_c = $t_m ^ $t_p;
+			$t_output .= chr( $t_c );
+		}
+
+		return $t_output;
+	}
+
+	# --------------------
+	# Return a binary md5 digest of a string
+	function radius_md5bin( $p_string ) {
+		$t_md5digest = md5( $p_string );
+		$t_binary = pack( "H" . strlen( $t_md5digest ), $t_md5digest );
+		
+		return $t_binary;
+	}
+
+?>
--- account_page.php.orig	Sun Jan 11 01:16:04 2004
+++ account_page.php	Mon May 24 21:25:31 2004
@@ -97,6 +97,18 @@
 		</td>
 	</tr>
 
+<?php } elseif ( RADIUS == config_get( 'login_method' ) ) { ?>
+
+	<!-- Username -->
+	<tr class="row-1">
+		<td class="category" width="25%">
+			<?php echo lang_get( 'username' ) ?>
+		</td>
+		<td width="75%">
+			<?php echo $u_username ?>
+		</td>
+	</tr>
+
 <?php } else { ?> <!-- Without LDAP -->
 
 	<!-- Username -->
--- config_defaults_inc.php.orig	Wed May 12 06:36:14 2004
+++ config_defaults_inc.php	Mon May 24 21:25:31 2004
@@ -569,6 +569,15 @@
 	$g_ldap_bind_passwd		= '';
 	$g_use_ldap_email		= OFF; # Should we send to the LDAP email address or what MySql tells us
 
+	#############################
+	# Mantis RADIUS Settings
+	#############################
+
+	$g_radius_server		= 'radius.example.com';
+	$g_radius_port			= '1812';
+	$g_radius_secret		= 'supersecret';
+	$g_radius_timeout		= '3';
+
 	############################
 	# Status Settings
 	############################
--- config_inc.php.sample.orig	Sun Feb  8 07:16:56 2004
+++ config_inc.php.sample	Mon May 24 21:25:31 2004
@@ -49,7 +49,7 @@
 	$g_return_path_email    = 'admin@example.com';
 
 	# --- login method ----------------
-	# CRYPT or PLAIN or MD5 or LDAP or BASIC_AUTH
+	# CRYPT or PLAIN or MD5 or LDAP or RADIUS or BASIC_AUTH
 	$g_login_method = MD5;
 
 	# --- email vars ------------------
--- core/authentication_api.php.orig	Thu Feb  5 06:15:16 2004
+++ core/authentication_api.php	Mon May 24 21:25:31 2004
@@ -148,7 +148,11 @@
 		if ( LDAP == $t_configured_login_method ) {
 			return ldap_authenticate( $p_user_id, $p_test_password );
 		}
-		
+
+		if ( RADIUS == $t_configured_login_method ) {
+			return radius_authenticate( $p_user_id, $p_test_password );
+		}
+
 		$t_password = user_get_field( $p_user_id, 'password' );
 		
 		$t_login_methods = Array(MD5, CRYPT, PLAIN);
--- core/constant_inc.php.orig	Wed Feb 11 16:16:28 2004
+++ core/constant_inc.php	Mon May 24 21:25:32 2004
@@ -96,6 +96,7 @@
 	define( 'MD5',				3 );
 	define( 'LDAP',				4 );
 	define( 'BASIC_AUTH',		5 );
+	define( 'RADIUS',			6 );
 
 	# file upload methods
 	define( 'DISK',			1 );
--- core/user_api.php.orig	Sun Jan 11 01:16:10 2004
+++ core/user_api.php	Mon May 24 21:25:32 2004
@@ -13,6 +13,7 @@
 	
 	require_once( $t_core_dir . 'email_api.php' );
 	require_once( $t_core_dir . 'ldap_api.php' );
+	require_once( $t_core_dir . 'radius_api.php' );
 
 	###########################################################################
 	# User API
mantis-0.18.3-radius.diff (10,945 bytes)   
mantis-radius.tar.gz (25,857 bytes)

Relationships

related to 0004235 closedvboctor mantisbt Support Generic Authentication through Plug-ins 
related to 0015282 assignedvboctor MantisTouch Support AD authentication via a RADIUS server 

Activities

vboctor

vboctor

2004-05-28 07:15

manager   ~0005617

Following is a link about RADIUS authentication, at the end it also has links to the relevant RFC:
http://www.untruth.org/~josh/security/radius/radius-auth.html

vboctor

vboctor

2004-05-28 07:20

manager   ~0005618

jcs, can you zip the added/modifed files and attach them to this issue? It will be easier to apply them against CVS this way.

I assume you already tested this against a radius server, right?

How keen are you to write a page about this in the manual? How to set it up, configure?

Are you able to support issues relating to the radius api? Given that we may not have the knowledge about RADIUS, or access to a RADIUS server.

jcs

jcs

2004-05-28 08:50

reporter   ~0005627

uploaded mantis-radius.tar.gz containing:
core/radius_api.php
account_page.php
config_defaults_inc.php
config_inc.php.sample
core/authentication_api.php
core/constant_inc.php
core/user_api.php

i have tested this against a radius server. i am using these radius patches on our production mantis server and have been for some time.

i can document the configuration. i will submit patches to the manual as soon as i have things written up.

i can support the radius api, there's not much to it.