Extreme
From RadiusExpert
Contents |
[edit]
Compatible Switches
RADIUS compatible devices from Extreme Networks
- Extreme i-Series Extreme Networks i-series Extremeware based switches (Blackdiamond 6800 series, Summit i-series, Summit 300 series, Summit 200 series, Alpine 3800 series).
- Extreme XOS Extreme Networks XOS based switches (Blackdiamond 10000, 12000 and 8000 series, X450 series, X250 series)
- Extreme WM Extreme Networks Wireless Management appliances and associated access points (WM100, WM1000, WM200, WM2000)
[edit]
Extreme CLI Authorisation
The Extremeware and XOS based switches support per-command authorisation in which each command typed at the switch console is authorised against the radius server:
The following AuthEXTREME.pm adds support for this feature to Radiator.
# AuthEXTREME.pm
#
# Object for handling Extreme Per Command Authorization.
#
# This file will be 'require'd only one time when the first Realm
# with an AuthType of EXTREME is found in the config file
#
# In this example accounting packets are ignored.
#
# Author: Martin Burton (mvb@sanger.ac.uk)
# Copyright (C) 2004 Martin Burton
# $Id:$
package Radius::AuthEXTREME;
@ISA = qw(Radius::AuthGeneric);
use Radius::AuthGeneric;
use strict;
#####################################################################
# This hash describes all the standards types of keywords understood by this
# class. If a keyword is not present in ConfigKeywords for this
# class, or any of its superclasses, Configurable will call sub keyword
# to parse the keyword
%Radius::AuthEXTREME::ConfigKeywords =
(
'ProfileFile' => 'string',
);
# Just a name for useful printing
my $class = 'AuthEXTREME';
&main::log($main::LOG_DEBUG, "$class loaded");
#####################################################################
# Constructs a new handler
# This will be called one for each <Realm ...> or <Handler ...> that
# specifies <AuthEXTREME ...>
# This instance will be destroyed when the server is reinitialised
sub new
{
my ($class, @args) = @_;
my $self = $class->SUPER::new(@args);
$self->log($main::LOG_DEBUG, "$class instantiated");
$self->log($main::LOG_DEBUG,
"$class using profile file $self->{ProfileFile}" );
#read the profiles file to populate $self->{Profiles}
$self->readProfileFile($self->{ProfileFile});
return $self;
}
#####################################################################
# Do per-instance default initialization
sub initialize
{
my ($self) = @_;
$self->SUPER::initialize;
$self->{ProfileFile} = './profiles';
}
sub readProfileFile
{
my ($self,$filename) = @_;
#Blank the profiles.
$self->{Profiles}={};
$self->log($main::LOG_DEBUG,"$class reading $filename");
if(!open(FILE,$filename))
{
$self->log($main::LOG_ERR,"Could not open profiles file: $filename");
return;
}
my ($profilename, $line, @lines);
#Set the end of paragraph marker to } to make reading the config file easier
local $/ = '}';
while (<FILE>)
{
chomp;
if ( /^(?#...)*\s*(\w+)\s*\{\s*(.*)/s )
{
$profilename = $1;
#create empty profile
$self->{Profiles}{$profilename}=[];
$line = $2;
chomp($line);
@lines = split(/\s*,?\s*\n/,$line);
foreach my $entry (@lines)
{
s/\*/\.\*/g for $entry;
push(@{$self->{Profiles}{$profilename}},$entry);
}
}
}
foreach my $pp (keys %{$self->{Profiles}})
{
$self->log($main::LOG_INFO,"$class PROFILE: $pp");
foreach my $kk ( @{$self->{Profiles}{$pp}} )
{
$self->log($main::LOG_INFO,"$class ENTRY: $kk");
}
}
}
#####################################################################
# Handle a request
#
sub handle_request
{
my ($self, $p, $dummy, $extra_checks) = @_;
my $user_name = $p->getUserName;
my $nas = $p->getNasId;
if ($p->code eq 'Access-Request')
{
my $checkflag = 0;
my $extreme_command = $p->get_attr('Extreme-Shell-Command');
if(defined($extreme_command))
{
my $extreme_profile = $p->{rp}->get_attr('Profile-Name');
if(defined($extreme_profile))
{
if(defined($self->{Profiles}->{$extreme_profile}))
{
foreach my $checkline (@{$self->{Profiles}->{$extreme_profile}})
{
if ( $extreme_command =~ m/^$checkline$/ )
{
$checkflag = 1;
}
}
if ($checkflag eq 0)
{
$self->log($main::LOG_INFO,"$class found no match");
}
}
else
{
#We haven't a clue about profile.
$self->log($main::LOG_INFO,"$class doesn't know about $extreme_profile");
$checkflag = 0;
}
}
else
{
#user with no profile!
$self->log($main::LOG_INFO,"$class has no profile for $user_name");
$checkflag = 0;
}
}
else {
# $self->log($main::LOG_INFO,"$class got no Shell Command");
# $checkflag = 1;
## The only time we get here is on first login to the switch.
return ($main::ACCEPT);
}
$p->{rp}->delete_attr('Profile-Name');
$self->adjustReply($p);
if ($checkflag eq 1)
{
$self->log($main::LOG_INFO,"$user_name: executed $extreme_command on $nas");
return ($main::ACCEPT);
}
else
{
$self->log($main::LOG_INFO,"$user_name: rejected $extreme_command on $nas");
return ($main::REJECT);
}
}
elsif ($p->code eq 'Accounting-Request')
{
# Handler will construct a generic reply for us
$self->log($main::LOG_INFO,"Login: ($nas) $user_name");
return ($main::ACCEPT);
}
else
{
# Handler will construct a generic reply for us
return ($main::ACCEPT);
}
}
1;
This may be specified within an AuthBy clause of the radius configuration file, at Sanger we do the following:
<Handler Realm=summits.sanger.ac.uk>
RewriteUsername s/^([^@]+).*/$1/
AuthByPolicy ContinueUntilReject
<AuthBy SYSTEM>
</AuthBy>
<AuthBy FILE>
Filename /radius/Radiator/summit_users
</AuthBy>
<AuthBy EXTREME>
ProfileFile /radius/Radiator/extreme_profiles
</AuthBy>
</Handler>
Entries within the summit_users file specify that per command authorisation should be enabled and the profile of each user:
abc
Service-Type = Administrative-User,
Extreme-CLI-Authorization = Enabled,
Profile-Name = ADMINUSER
def
Service-Type = Administrative-User,
Extreme-CLI-Authorization = Enabled,
Profile-Name = VLANUSER
ghi
Service-Type = Administrative-User,
Extreme-CLI-Authorization = Enabled,
Profile-Name = SLBUSER
The extreme_profiles file defines profiles that contain the commands that may be used by particular groups of users:
# Switch admin users. Everything allowed!
ADMINUSER {
*
}
# Normal users.
VLANUSER {
show vlan,
show vlan *,
show ports *,
show fdb *,
show ipfdb *,
configure vlan * add ports *,
configure vlan * delete ports *,
configure ports *,
enable ports *,
disable ports *,
show log *,
show switch,
ping *,
save
}
# Restricted to SLB admin commands
SLBUSER
{
show slb *,
enable slb node *,
disable slb node *,
clear slb connections,
save
}
The dictionary contains the following VSAs:
VENDORATTR 1916 Extreme-CLI-Authorization 201 integer VENDORATTR 1916 Extreme-Shell-Command 202 string VENDORATTR 1916 Extreme-Netlogin-Vlan 203 string VENDORATTR 1916 Extreme-Netlogin-Url 204 string VENDORATTR 1916 Extreme-Netlogin-Url-Desc 205 string VENDORATTR 1916 Extreme-Netlogin-Only 206 integer VENDORATTR 1916 Extreme-User-Location 208 string VENDORATTR 1916 Extreme-Netlogin-VLAN-Tag 209 integer VALUE Extreme-CLI-Authorization Disabled 0 VALUE Extreme-CLI-Authorization Enabled 1 VALUE Extreme-Netlogin-Only Disabled 0 VALUE Extreme-Netlogin-Only Enabled 1

