blob: 660ad331afaabbb2fe7ebab46ea322e904323134 [file] [log] [blame]
Ari Saha89831742015-06-26 10:31:48 -07001/*
Amit Ghoshc9ac1e52017-07-28 12:31:18 +01002 * Copyright 2017-present Open Networking Foundation
Ari Saha89831742015-06-26 10:31:48 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Matteo Scandolocf847b82019-04-26 15:00:00 -070016package org.opencord.aaa.impl;
Ari Saha89831742015-06-26 10:31:48 -070017
Shubham Sharma4900ce62019-06-19 14:18:50 +000018import com.google.common.base.Strings;
Jonathan Hart612651f2019-11-25 09:21:43 -080019import com.google.common.collect.Maps;
Matteo Scandolo9510e5d2020-09-24 17:31:52 -070020
Andrea Campanellac4781e62020-10-08 12:58:45 +020021import static java.util.concurrent.Executors.newSingleThreadExecutor;
Matteo Scandolo9510e5d2020-09-24 17:31:52 -070022import static org.onlab.util.Tools.groupedThreads;
Girish Kumar064084c2020-02-04 08:32:46 +000023import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
Matteo Scandolo9510e5d2020-09-24 17:31:52 -070024import static org.opencord.aaa.impl.OsgiPropertyConstants.*;
Girish Kumar064084c2020-02-04 08:32:46 +000025import static org.slf4j.LoggerFactory.getLogger;
26
27import com.google.common.collect.Sets;
Matteo Scandoloe033c262020-10-14 11:37:39 -070028
Girish Kumar064084c2020-02-04 08:32:46 +000029import java.net.InetAddress;
30import java.net.UnknownHostException;
31import java.nio.ByteBuffer;
32import java.util.Dictionary;
33import java.util.HashSet;
34import java.util.Arrays;
35import java.util.List;
Hardik Windlassd0b49692020-02-26 18:17:14 +000036import java.util.Map;
Girish Kumar064084c2020-02-04 08:32:46 +000037import java.util.Set;
38import java.util.Map.Entry;
39
Jonathan Hart932bedc2018-07-12 13:46:09 -070040import org.apache.commons.lang3.builder.ToStringBuilder;
Jonathan Hart4731dd92018-05-02 17:30:05 -070041import org.onlab.packet.DeserializationException;
Jonathan Harta46dddf2015-06-30 15:31:20 -070042import org.onlab.packet.EAP;
43import org.onlab.packet.EAPOL;
44import org.onlab.packet.EthType;
Ari Saha89831742015-06-26 10:31:48 -070045import org.onlab.packet.Ethernet;
Ari Saha89831742015-06-26 10:31:48 -070046import org.onlab.packet.MacAddress;
Jonathan Harta46dddf2015-06-30 15:31:20 -070047import org.onlab.packet.RADIUS;
48import org.onlab.packet.RADIUSAttribute;
Jonathan Hart9d1ce802020-01-28 10:45:08 -080049import org.onlab.util.KryoNamespace;
kartikey dubeye1545422019-05-22 12:53:45 +000050import org.onlab.util.Tools;
51import org.onosproject.cfg.ComponentConfigService;
Ari Saha89831742015-06-26 10:31:48 -070052import org.onosproject.core.ApplicationId;
53import org.onosproject.core.CoreService;
Jonathan Hart5db44532018-07-12 18:13:54 -070054import org.onosproject.event.AbstractListenerManager;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010055import org.onosproject.mastership.MastershipService;
Ari Saha89831742015-06-26 10:31:48 -070056import org.onosproject.net.ConnectPoint;
57import org.onosproject.net.DeviceId;
Ari Saha89831742015-06-26 10:31:48 -070058import org.onosproject.net.PortNumber;
Ray Milkeyfcb623d2015-10-01 16:48:18 -070059import org.onosproject.net.config.ConfigFactory;
60import org.onosproject.net.config.NetworkConfigEvent;
61import org.onosproject.net.config.NetworkConfigListener;
62import org.onosproject.net.config.NetworkConfigRegistry;
Amit Ghoshf739be52017-09-21 15:49:37 +010063import org.onosproject.net.device.DeviceEvent;
64import org.onosproject.net.device.DeviceListener;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010065import org.onosproject.net.device.DeviceService;
Ari Saha89831742015-06-26 10:31:48 -070066import org.onosproject.net.flow.DefaultTrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070067import org.onosproject.net.flow.TrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070068import org.onosproject.net.packet.DefaultOutboundPacket;
69import org.onosproject.net.packet.InboundPacket;
70import org.onosproject.net.packet.OutboundPacket;
71import org.onosproject.net.packet.PacketContext;
Ari Saha89831742015-06-26 10:31:48 -070072import org.onosproject.net.packet.PacketProcessor;
73import org.onosproject.net.packet.PacketService;
Jonathan Hartc41227c2020-01-28 16:56:49 -080074import org.onosproject.store.serializers.KryoNamespaces;
Jonathan Hart9d1ce802020-01-28 10:45:08 -080075import org.onosproject.store.service.ConsistentMap;
76import org.onosproject.store.service.MapEvent;
77import org.onosproject.store.service.MapEventListener;
78import org.onosproject.store.service.Serializer;
79import org.onosproject.store.service.StorageService;
Matteo Scandolocf847b82019-04-26 15:00:00 -070080import org.opencord.aaa.AaaConfig;
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +000081import org.opencord.aaa.AaaMachineStatisticsEvent;
82import org.opencord.aaa.AaaMachineStatisticsService;
83import org.opencord.aaa.AaaSupplicantMachineStats;
Matteo Scandolocf847b82019-04-26 15:00:00 -070084import org.opencord.aaa.AuthenticationEvent;
85import org.opencord.aaa.AuthenticationEventListener;
Jonathan Hart612651f2019-11-25 09:21:43 -080086import org.opencord.aaa.AuthenticationRecord;
Matteo Scandolocf847b82019-04-26 15:00:00 -070087import org.opencord.aaa.AuthenticationService;
kartikey dubeye1545422019-05-22 12:53:45 +000088import org.opencord.aaa.AuthenticationStatisticsService;
Matteo Scandolocf847b82019-04-26 15:00:00 -070089import org.opencord.aaa.RadiusCommunicator;
Shubham Sharma4900ce62019-06-19 14:18:50 +000090import org.opencord.aaa.RadiusOperationalStatusEvent;
91import org.opencord.aaa.RadiusOperationalStatusService;
92import org.opencord.aaa.RadiusOperationalStatusService.RadiusOperationalStatusEvaluationMode;
Matteo Scandolocf847b82019-04-26 15:00:00 -070093import org.opencord.aaa.StateMachineDelegate;
Gamze Abaka1cfdb192018-10-25 11:39:19 +000094import org.opencord.sadis.BaseInformationService;
95import org.opencord.sadis.SadisService;
96import org.opencord.sadis.SubscriberAndDeviceInformation;
kartikey dubeye1545422019-05-22 12:53:45 +000097import org.osgi.service.component.ComponentContext;
Carmelo Cascone58b53292019-09-30 12:35:31 -070098import org.osgi.service.component.annotations.Activate;
Shubham Sharma4900ce62019-06-19 14:18:50 +000099import org.osgi.service.component.annotations.Component;
100import org.osgi.service.component.annotations.Deactivate;
101import org.osgi.service.component.annotations.Modified;
102import org.osgi.service.component.annotations.Reference;
103import org.osgi.service.component.annotations.ReferenceCardinality;
Ari Saha89831742015-06-26 10:31:48 -0700104import org.slf4j.Logger;
105
Shubham Sharma4900ce62019-06-19 14:18:50 +0000106import javax.crypto.Mac;
107import javax.crypto.spec.SecretKeySpec;
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800108import java.util.Optional;
Jonathan Hart612651f2019-11-25 09:21:43 -0800109import java.util.concurrent.ConcurrentMap;
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700110import java.util.concurrent.ExecutorService;
kartikey dubeye1545422019-05-22 12:53:45 +0000111import java.util.concurrent.Executors;
112import java.util.concurrent.ScheduledExecutorService;
113import java.util.concurrent.ScheduledFuture;
114import java.util.concurrent.TimeUnit;
Vijaykumar Kushwaha056e4cd2019-08-06 13:16:25 +0000115
Ari Saha89831742015-06-26 10:31:48 -0700116/**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700117 * AAA application for ONOS.
Ari Saha89831742015-06-26 10:31:48 -0700118 */
Carmelo Cascone58b53292019-09-30 12:35:31 -0700119@Component(immediate = true, property = {
Shubham Sharma4900ce62019-06-19 14:18:50 +0000120 OPERATIONAL_STATUS_SERVER_EVENT_GENERATION + ":Integer=" + OPERATIONAL_STATUS_SERVER_EVENT_GENERATION_DEFAULT,
121 OPERATIONAL_STATUS_SERVER_TIMEOUT + ":Integer=" + OPERATIONAL_STATUS_SERVER_TIMEOUT_DEFAULT,
122 STATUS_SERVER_MODE + ":String=" + STATUS_SERVER_MODE_DEFAULT,
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700123 PACKET_PROCESSOR_THREADS + ":Integer=" + PACKET_PROCESSOR_THREADS_DEFAULT,
Carmelo Cascone58b53292019-09-30 12:35:31 -0700124})
Jonathan Hart5db44532018-07-12 18:13:54 -0700125public class AaaManager
126 extends AbstractListenerManager<AuthenticationEvent, AuthenticationEventListener>
127 implements AuthenticationService {
128
Charles Chandf7ff862017-01-20 11:22:05 -0800129 private static final String APP_NAME = "org.opencord.aaa";
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700130 private static final int STATE_MACHINE_THREADS = 3;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700131
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700132 private final Logger log = getLogger(getClass());
Ray Milkeyf51eba22015-09-25 10:24:23 -0700133
Carmelo Cascone58b53292019-09-30 12:35:31 -0700134 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700135 protected CoreService coreService;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700136
Carmelo Cascone58b53292019-09-30 12:35:31 -0700137 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800138 protected StorageService storageService;
139
140 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700141 protected PacketService packetService;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700142
Carmelo Cascone58b53292019-09-30 12:35:31 -0700143 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700144 protected NetworkConfigRegistry netCfgService;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700145
Carmelo Cascone58b53292019-09-30 12:35:31 -0700146 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100147 protected DeviceService deviceService;
148
Carmelo Cascone58b53292019-09-30 12:35:31 -0700149 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Gamze Abaka1cfdb192018-10-25 11:39:19 +0000150 protected SadisService sadisService;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100151
Carmelo Cascone58b53292019-09-30 12:35:31 -0700152 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100153 protected MastershipService mastershipService;
154
Carmelo Cascone58b53292019-09-30 12:35:31 -0700155 @Reference(cardinality = ReferenceCardinality.MANDATORY)
kartikey dubeye1545422019-05-22 12:53:45 +0000156 protected AuthenticationStatisticsService aaaStatisticsManager;
Gamze Abaka1cfdb192018-10-25 11:39:19 +0000157
Carmelo Cascone58b53292019-09-30 12:35:31 -0700158 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +0000159 protected AaaMachineStatisticsService aaaSupplicantStatsManager;
160
161 @Reference(cardinality = ReferenceCardinality.MANDATORY)
kartikey dubeye1545422019-05-22 12:53:45 +0000162 protected ComponentConfigService cfgService;
163
Shubham Sharma4900ce62019-06-19 14:18:50 +0000164 @Reference(cardinality = ReferenceCardinality.MANDATORY)
165 protected RadiusOperationalStatusService radiusOperationalStatusService;
166
kartikey dubeye1545422019-05-22 12:53:45 +0000167 protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
Amit Ghoshf739be52017-09-21 15:49:37 +0100168 private final DeviceListener deviceListener = new InternalDeviceListener();
169
Shubham Sharma4900ce62019-06-19 14:18:50 +0000170 // Properties
Shubham Sharma4900ce62019-06-19 14:18:50 +0000171 private int operationalStatusEventGenerationPeriodInSeconds = OPERATIONAL_STATUS_SERVER_EVENT_GENERATION_DEFAULT;
172 private int operationalStatusServerTimeoutInSeconds = OPERATIONAL_STATUS_SERVER_TIMEOUT_DEFAULT;
173 protected String operationalStatusEvaluationMode = STATUS_SERVER_MODE_DEFAULT;
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700174 /**
175 * Number of threads used to process the packet.
176 */
177 protected int packetProcessorThreads = PACKET_PROCESSOR_THREADS_DEFAULT;
kartikey dubeye1545422019-05-22 12:53:45 +0000178
Jonathan Hart612651f2019-11-25 09:21:43 -0800179 private IdentifierManager idManager;
180
181 private ConcurrentMap<String, StateMachine> stateMachines;
182
Hardik Windlassd0b49692020-02-26 18:17:14 +0000183 private ConsistentMap<ConnectPoint, AuthenticationRecord> authenticationsConsistentMap;
184 private Map<ConnectPoint, AuthenticationRecord> authentications;
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800185
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700186 // NAS IP address
187 protected InetAddress nasIpAddress;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100188
189 // self MAC address
Jonathan Hart5db44532018-07-12 18:13:54 -0700190 protected String nasMacAddress;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100191
192 // Parsed RADIUS server addresses
193 protected InetAddress radiusIpAddress;
194
195 // MAC address of RADIUS server or net hop router
196 protected String radiusMacAddress;
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700197
198 // RADIUS server secret
199 protected String radiusSecret;
200
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100201 // bindings
202 protected CustomizationInfo customInfo;
Ray Milkey5d99bd12015-10-06 15:41:30 -0700203
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700204 // our application-specific event handler
205 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
Ray Milkeyf51eba22015-09-25 10:24:23 -0700206
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700207 // our unique identifier
208 private ApplicationId appId;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700209
Shubham Sharma1e43c562019-06-19 14:18:12 +0000210 // TimeOut time for cleaning up stateMachines stuck due to pending AAA/EAPOL message.
211 protected int cleanupTimerTimeOutInMins;
212
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100213 // Setup specific customization/attributes on the RADIUS packets
214 PacketCustomizer pktCustomizer;
Ray Milkey967776a2015-10-07 14:37:17 -0700215
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100216 // packet customizer to use
217 private String customizer;
218
219 // Type of connection to use to communicate with Radius server, options are
220 // "socket" or "packet_out"
221 private String radiusConnectionType;
222
Jonathan Hart5db44532018-07-12 18:13:54 -0700223 // Object for the specific type of communication with the RADIUS
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100224 // server, socket based or packet_out based
225 RadiusCommunicator impl = null;
226
227 // latest configuration
228 AaaConfig newCfg;
Ray Milkey967776a2015-10-07 14:37:17 -0700229
Shubham Sharma4900ce62019-06-19 14:18:50 +0000230 ScheduledFuture<?> scheduledStatusServerChecker;
kartikey dubeye1545422019-05-22 12:53:45 +0000231 String configuredAaaServerAddress;
Jonathan Hartc41227c2020-01-28 16:56:49 -0800232 HashSet<Byte> outPacketSet = new HashSet<>();
233 HashSet<Byte> outPacketSupp = new HashSet<>();
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000234 static final List<Byte> VALID_EAPOL_TYPE = Arrays.asList(EAPOL.EAPOL_START, EAPOL.EAPOL_LOGOFF, EAPOL.EAPOL_PACKET);
235 static final int HEADER_LENGTH = 4;
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700236 // Configuration properties factory
237 private final ConfigFactory factory =
Jonathan Hart092dfb22015-11-16 23:05:21 -0800238 new ConfigFactory<ApplicationId, AaaConfig>(APP_SUBJECT_FACTORY,
Matteo Scandoloe033c262020-10-14 11:37:39 -0700239 AaaConfig.class,
240 "AAA") {
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700241 @Override
Jonathan Hart092dfb22015-11-16 23:05:21 -0800242 public AaaConfig createConfig() {
243 return new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700244 }
245 };
Ray Milkeyf51eba22015-09-25 10:24:23 -0700246
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700247 // Listener for config changes
248 private final InternalConfigListener cfgListener = new InternalConfigListener();
Ari Saha89831742015-06-26 10:31:48 -0700249
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800250 private final InternalMapEventListener mapListener = new InternalMapEventListener();
251
Jonathan Hart5db44532018-07-12 18:13:54 -0700252 private StateMachineDelegate delegate = new InternalStateMachineDelegate();
253
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700254 protected ExecutorService packetProcessorExecutor;
255 protected ScheduledExecutorService serverStatusAndStateMachineTimeoutExecutor;
Matteo Scandoloe033c262020-10-14 11:37:39 -0700256
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700257 /**
258 * Builds an EAPOL packet based on the given parameters.
259 *
260 * @param dstMac destination MAC address
261 * @param srcMac source MAC address
262 * @param vlan vlan identifier
263 * @param eapolType EAPOL type
264 * @param eap EAP payload
265 * @return Ethernet frame
266 */
267 private static Ethernet buildEapolResponse(MacAddress dstMac, MacAddress srcMac,
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100268 short vlan, byte eapolType, EAP eap, byte priorityCode) {
Ari Saha89831742015-06-26 10:31:48 -0700269
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700270 Ethernet eth = new Ethernet();
271 eth.setDestinationMACAddress(dstMac.toBytes());
272 eth.setSourceMACAddress(srcMac.toBytes());
273 eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
274 if (vlan != Ethernet.VLAN_UNTAGGED) {
275 eth.setVlanID(vlan);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100276 eth.setPriorityCode(priorityCode);
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700277 }
278 //eapol header
279 EAPOL eapol = new EAPOL();
280 eapol.setEapolType(eapolType);
281 eapol.setPacketLength(eap.getLength());
Ari Saha89831742015-06-26 10:31:48 -0700282
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700283 //eap part
284 eapol.setPayload(eap);
285
286 eth.setPayload(eapol);
287 eth.setPad(true);
288 return eth;
289 }
Ari Saha89831742015-06-26 10:31:48 -0700290
Ari Saha89831742015-06-26 10:31:48 -0700291 @Activate
kartikey dubeye1545422019-05-22 12:53:45 +0000292 public void activate(ComponentContext context) {
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700293
Jonathan Hart612651f2019-11-25 09:21:43 -0800294 idManager = new IdentifierManager();
295 stateMachines = Maps.newConcurrentMap();
Charles Chandf7ff862017-01-20 11:22:05 -0800296 appId = coreService.registerApplication(APP_NAME);
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800297
298 KryoNamespace authSerializer = KryoNamespace.newBuilder()
Jonathan Hartc41227c2020-01-28 16:56:49 -0800299 .register(KryoNamespaces.API)
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800300 .register(AuthenticationRecord.class)
301 .build();
302
Hardik Windlassd0b49692020-02-26 18:17:14 +0000303 authenticationsConsistentMap = storageService.<ConnectPoint, AuthenticationRecord>consistentMapBuilder()
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800304 .withApplicationId(appId)
305 .withName("authentications")
306 .withSerializer(Serializer.using(authSerializer))
307 .build();
Hardik Windlassd0b49692020-02-26 18:17:14 +0000308 authenticationsConsistentMap.addListener(mapListener);
309 authentications = authenticationsConsistentMap.asJavaMap();
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800310
Jonathan Hart5db44532018-07-12 18:13:54 -0700311 eventDispatcher.addSink(AuthenticationEvent.class, listenerRegistry);
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400312 netCfgService.addListener(cfgListener);
313 netCfgService.registerConfigFactory(factory);
kartikey dubeye1545422019-05-22 12:53:45 +0000314 cfgService.registerProperties(getClass());
315 modified(context);
Gamze Abaka1cfdb192018-10-25 11:39:19 +0000316 subsService = sadisService.getSubscriberInfoService();
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530317 customInfo = new CustomizationInfo(subsService, deviceService);
Jonathan Hart092dfb22015-11-16 23:05:21 -0800318 cfgListener.reconfigureNetwork(netCfgService.getConfig(appId, AaaConfig.class));
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400319 log.info("Starting with config {} {}", this, newCfg);
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530320 configureRadiusCommunication();
Ari Saha89831742015-06-26 10:31:48 -0700321 // register our event handler
Brian O'Connord9c7da02015-07-29 17:49:24 -0700322 packetService.addProcessor(processor, PacketProcessor.director(2));
Jonathan Hart5db44532018-07-12 18:13:54 -0700323 StateMachine.setDelegate(delegate);
Shubham Sharma1e43c562019-06-19 14:18:12 +0000324 cleanupTimerTimeOutInMins = newCfg.sessionCleanupTimer();
325 StateMachine.setcleanupTimerTimeOutInMins(cleanupTimerTimeOutInMins);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100326 impl.initializeLocalState(newCfg);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100327 impl.requestIntercepts();
Amit Ghoshf739be52017-09-21 15:49:37 +0100328 deviceService.addListener(deviceListener);
kartikey dubeye1545422019-05-22 12:53:45 +0000329 getConfiguredAaaServerAddress();
Shubham Sharma4900ce62019-06-19 14:18:50 +0000330 radiusOperationalStatusService.initialize(nasIpAddress.getAddress(), radiusSecret, impl);
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700331 serverStatusAndStateMachineTimeoutExecutor = Executors.newScheduledThreadPool(STATE_MACHINE_THREADS,
Matteo Scandoloe033c262020-10-14 11:37:39 -0700332 groupedThreads("onos/aaa", "aaa-machine-%d", log));
Shubham Sharma4900ce62019-06-19 14:18:50 +0000333
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700334 scheduledStatusServerChecker = serverStatusAndStateMachineTimeoutExecutor.scheduleAtFixedRate(
335 new ServerStatusChecker(), 0,
336 operationalStatusEventGenerationPeriodInSeconds, TimeUnit.SECONDS);
Amit Ghoshf739be52017-09-21 15:49:37 +0100337
Jian Li13c67162015-12-09 13:20:34 -0800338 log.info("Started");
Ari Saha89831742015-06-26 10:31:48 -0700339 }
340
341 @Deactivate
kartikey dubeye1545422019-05-22 12:53:45 +0000342 public void deactivate(ComponentContext context) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100343 impl.withdrawIntercepts();
Ari Saha89831742015-06-26 10:31:48 -0700344 packetService.removeProcessor(processor);
Deepa Vaddireddyb9c24c62017-09-21 13:45:30 +0530345 netCfgService.removeListener(cfgListener);
kartikey dubeye1545422019-05-22 12:53:45 +0000346 cfgService.unregisterProperties(getClass(), false);
Jonathan Hart5db44532018-07-12 18:13:54 -0700347 StateMachine.unsetDelegate(delegate);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100348 impl.deactivate();
Amit Ghoshf739be52017-09-21 15:49:37 +0100349 deviceService.removeListener(deviceListener);
Jonathan Hart5db44532018-07-12 18:13:54 -0700350 eventDispatcher.removeSink(AuthenticationEvent.class);
Shubham Sharma4900ce62019-06-19 14:18:50 +0000351 scheduledStatusServerChecker.cancel(true);
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700352 serverStatusAndStateMachineTimeoutExecutor.shutdown();
353 packetProcessorExecutor.shutdown();
Hardik Windlassd0b49692020-02-26 18:17:14 +0000354 authenticationsConsistentMap.removeListener(mapListener);
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800355
Jian Li13c67162015-12-09 13:20:34 -0800356 log.info("Stopped");
Ray Milkey967776a2015-10-07 14:37:17 -0700357 }
Matteo Scandoloe033c262020-10-14 11:37:39 -0700358
kartikey dubeye1545422019-05-22 12:53:45 +0000359 @Modified
360 public void modified(ComponentContext context) {
Shubham Sharma4900ce62019-06-19 14:18:50 +0000361 Dictionary<String, Object> properties = context.getProperties();
362
Jonathan Hartc41227c2020-01-28 16:56:49 -0800363 String s = Tools.get(properties, "operationalStatusEventGenerationPeriodInSeconds");
Shubham Sharma4900ce62019-06-19 14:18:50 +0000364 operationalStatusEventGenerationPeriodInSeconds = Strings.isNullOrEmpty(s)
365 ? OPERATIONAL_STATUS_SERVER_EVENT_GENERATION_DEFAULT
Matteo Scandoloe033c262020-10-14 11:37:39 -0700366 : Integer.parseInt(s.trim());
Shubham Sharma4900ce62019-06-19 14:18:50 +0000367
368 s = Tools.get(properties, "operationalStatusServerTimeoutInSeconds");
369 operationalStatusServerTimeoutInSeconds = Strings.isNullOrEmpty(s) ? OPERATIONAL_STATUS_SERVER_TIMEOUT_DEFAULT
370 : Integer.parseInt(s.trim());
371
372 s = Tools.get(properties, "operationalStatusEvaluationMode");
373 String newEvaluationModeString = Strings.isNullOrEmpty(s) ? STATUS_SERVER_MODE_DEFAULT : s.trim();
374
375 radiusOperationalStatusService
Matteo Scandoloe033c262020-10-14 11:37:39 -0700376 .setOperationalStatusServerTimeoutInMillis(operationalStatusServerTimeoutInSeconds * 1000);
Shubham Sharma4900ce62019-06-19 14:18:50 +0000377 RadiusOperationalStatusEvaluationMode newEvaluationMode =
378 RadiusOperationalStatusEvaluationMode.getValue(newEvaluationModeString);
379 if (newEvaluationMode != null) {
380 radiusOperationalStatusService.setRadiusOperationalStatusEvaluationMode(newEvaluationMode);
381 operationalStatusEvaluationMode = newEvaluationModeString;
382 } else {
383 properties.put("operationalStatusEvaluationMode", operationalStatusEvaluationMode);
384 }
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700385
386 s = Tools.get(properties, PACKET_PROCESSOR_THREADS);
387 int oldpacketProcessorThreads = packetProcessorThreads;
388 packetProcessorThreads = Strings.isNullOrEmpty(s) ? oldpacketProcessorThreads
389 : Integer.parseInt(s.trim());
390 if (packetProcessorExecutor == null || oldpacketProcessorThreads != packetProcessorThreads) {
391 if (packetProcessorExecutor != null) {
392 packetProcessorExecutor.shutdown();
393 }
Matteo Scandoloe033c262020-10-14 11:37:39 -0700394 packetProcessorExecutor = newSingleThreadExecutor(
395 groupedThreads("onos/aaa", "aaa-packet-%d", log));
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700396 }
kartikey dubeye1545422019-05-22 12:53:45 +0000397 }
398
Shubham Sharmacf5e5032019-11-26 11:09:21 +0000399 protected void configureRadiusCommunication() {
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530400 if (radiusConnectionType.toLowerCase().equals("socket")) {
401 impl = new SocketBasedRadiusCommunicator(appId, packetService, this);
402 } else {
403 impl = new PortBasedRadiusCommunicator(appId, packetService, mastershipService,
Matteo Scandoloe033c262020-10-14 11:37:39 -0700404 deviceService, subsService, pktCustomizer, this);
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530405 }
406 }
407
408 private void configurePacketCustomizer() {
409 switch (customizer.toLowerCase()) {
410 case "sample":
411 pktCustomizer = new SamplePacketCustomizer(customInfo);
412 log.info("Created SamplePacketCustomizer");
413 break;
Saurav Dase72358a2018-11-13 21:56:46 -0800414 case "att":
415 pktCustomizer = new AttPacketCustomizer(customInfo);
416 log.info("Created AttPacketCustomizer");
417 break;
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530418 default:
419 pktCustomizer = new PacketCustomizer(customInfo);
420 log.info("Created default PacketCustomizer");
421 break;
422 }
423 }
424
kartikey dubeye1545422019-05-22 12:53:45 +0000425 private void getConfiguredAaaServerAddress() {
426 try {
427 InetAddress address;
428 if (newCfg.radiusHostName() != null) {
429 address = InetAddress.getByName(newCfg.radiusHostName());
430 } else {
Matteo Scandoloe033c262020-10-14 11:37:39 -0700431 address = newCfg.radiusIp();
kartikey dubeye1545422019-05-22 12:53:45 +0000432 }
433
434 configuredAaaServerAddress = address.getHostAddress();
435 } catch (UnknownHostException uhe) {
436 log.warn("Unable to resolve host {}", newCfg.radiusHostName());
437 }
438 }
439
Vijaykumar Kushwaha056e4cd2019-08-06 13:16:25 +0000440 private void checkReceivedPacketForValidValidator(RADIUS radiusPacket, byte[] requestAuthenticator) {
441 if (!checkResponseMessageAuthenticator(radiusSecret, radiusPacket, requestAuthenticator)) {
kartikey dubeye1545422019-05-22 12:53:45 +0000442 aaaStatisticsManager.getAaaStats().increaseInvalidValidatorsRx();
443 }
444 }
Vijaykumar Kushwaha056e4cd2019-08-06 13:16:25 +0000445
446 private boolean checkResponseMessageAuthenticator(String key, RADIUS radiusPacket, byte[] requestAuthenticator) {
447 byte[] newHash = new byte[16];
448 Arrays.fill(newHash, (byte) 0);
449 byte[] messageAuthenticator = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH).getValue();
450 byte[] authenticator = radiusPacket.getAuthenticator();
451 radiusPacket.updateAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH, newHash);
452 radiusPacket.setAuthenticator(requestAuthenticator);
453 // Calculate the MD5 HMAC based on the message
454 try {
455 SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "HmacMD5");
456 Mac mac = Mac.getInstance("HmacMD5");
457 mac.init(keySpec);
458 newHash = mac.doFinal(radiusPacket.serialize());
459 } catch (Exception e) {
460 log.error("Failed to generate message authenticator: {}", e.getMessage());
461 }
462 radiusPacket.updateAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH, messageAuthenticator);
463 radiusPacket.setAuthenticator(authenticator);
464 // Compare the calculated Message-Authenticator with the one in the message
465 return Arrays.equals(newHash, messageAuthenticator);
466 }
Matteo Scandoloe033c262020-10-14 11:37:39 -0700467
kartikey dubeye1545422019-05-22 12:53:45 +0000468 public void checkForPacketFromUnknownServer(String hostAddress) {
Matteo Scandoloe033c262020-10-14 11:37:39 -0700469 if (!hostAddress.equals(configuredAaaServerAddress)) {
470 getConfiguredAaaServerAddress();
kartikey dubeye1545422019-05-22 12:53:45 +0000471 if (!hostAddress.equals(configuredAaaServerAddress)) {
Matteo Scandoloe033c262020-10-14 11:37:39 -0700472 aaaStatisticsManager.getAaaStats().incrementUnknownServerRx();
kartikey dubeye1545422019-05-22 12:53:45 +0000473 }
Matteo Scandoloe033c262020-10-14 11:37:39 -0700474 }
kartikey dubeye1545422019-05-22 12:53:45 +0000475 }
476
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100477 /**
478 * Send RADIUS packet to the RADIUS server.
479 *
480 * @param radiusPacket RADIUS packet to be sent to server.
481 * @param inPkt Incoming EAPOL packet
482 */
483 protected void sendRadiusPacket(RADIUS radiusPacket, InboundPacket inPkt) {
kartikey dubeye1545422019-05-22 12:53:45 +0000484 outPacketSet.add(radiusPacket.getIdentifier());
485 aaaStatisticsManager.getAaaStats().increaseOrDecreasePendingRequests(true);
486 aaaStatisticsManager.getAaaStats().increaseAccessRequestsTx();
Shubham Sharma4900ce62019-06-19 14:18:50 +0000487 aaaStatisticsManager.putOutgoingIdentifierToMap(radiusPacket.getIdentifier());
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100488 impl.sendRadiusPacket(radiusPacket, inPkt);
489 }
Ray Milkey967776a2015-10-07 14:37:17 -0700490
Jonathan Hart612651f2019-11-25 09:21:43 -0800491 /**
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100492 * Handles RADIUS packets.
493 *
494 * @param radiusPacket RADIUS packet coming from the RADIUS server.
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100495 */
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700496 public void handleRadiusPacket(RADIUS radiusPacket) {
Andrea Campanellac4781e62020-10-08 12:58:45 +0200497 if (log.isTraceEnabled()) {
498 log.trace("Received RADIUS packet {}", radiusPacket);
499 }
500 if (radiusOperationalStatusService.isRadiusResponseForOperationalStatus(radiusPacket.getIdentifier())) {
501 radiusOperationalStatusService.handleRadiusPacketForOperationalStatus(radiusPacket);
502 return;
503 }
Jonathan Hart612651f2019-11-25 09:21:43 -0800504
Andrea Campanellac4781e62020-10-08 12:58:45 +0200505 RequestIdentifier identifier = RequestIdentifier.of(radiusPacket.getIdentifier());
506 String sessionId = idManager.getSessionId(identifier);
Jonathan Hart612651f2019-11-25 09:21:43 -0800507
Andrea Campanellac4781e62020-10-08 12:58:45 +0200508 if (sessionId == null) {
509 log.error("Invalid packet identifier {}, could not find corresponding "
510 + "state machine ... exiting", radiusPacket.getIdentifier());
511 aaaStatisticsManager.getAaaStats().incrementNumberOfSessionsExpired();
512 aaaStatisticsManager.getAaaStats().countDroppedResponsesRx();
513 return;
514 }
Jonathan Hart612651f2019-11-25 09:21:43 -0800515
Andrea Campanellac4781e62020-10-08 12:58:45 +0200516 idManager.releaseIdentifier(identifier);
517 StateMachine stateMachine = stateMachines.get(sessionId);
518 if (stateMachine == null) {
519 log.error("Invalid packet identifier {}, could not find corresponding "
520 + "state machine ... exiting", radiusPacket.getIdentifier());
521 aaaStatisticsManager.getAaaStats().incrementNumberOfSessionsExpired();
522 aaaStatisticsManager.getAaaStats().countDroppedResponsesRx();
523 return;
524 }
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +0000525
Andrea Campanellac4781e62020-10-08 12:58:45 +0200526 //instance of StateMachine using the sessionId for updating machine stats
527 StateMachine machineStats = stateMachines.get(stateMachine.sessionId());
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +0000528
Andrea Campanellac4781e62020-10-08 12:58:45 +0200529 EAP eapPayload;
530 Ethernet eth;
531 checkReceivedPacketForValidValidator(radiusPacket, stateMachine.requestAuthenticator());
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +0000532
Andrea Campanellac4781e62020-10-08 12:58:45 +0200533 //increasing packets and octets received from server
534 machineStats.incrementTotalPacketsReceived();
535 try {
536 machineStats.incrementTotalOctetReceived(radiusPacket.decapsulateMessage().getLength());
537 } catch (DeserializationException e) {
538 log.error(e.getMessage());
539 return;
540 }
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700541
Andrea Campanellac4781e62020-10-08 12:58:45 +0200542 if (outPacketSet.contains(radiusPacket.getIdentifier())) {
543 aaaStatisticsManager.getAaaStats().increaseOrDecreasePendingRequests(false);
544 outPacketSet.remove(new Byte(radiusPacket.getIdentifier()));
545 }
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700546
Andrea Campanellac4781e62020-10-08 12:58:45 +0200547 MacAddress dstMac = stateMachine.supplicantAddress();
548 ConnectPoint supplicantCp = stateMachine.supplicantConnectpoint();
549 switch (radiusPacket.getCode()) {
550 case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE:
Matteo Scandoloe033c262020-10-14 11:37:39 -0700551 log.debug("RADIUS packet: RADIUS_CODE_ACCESS_CHALLENGE for dev/port: {}/{} " +
552 "with MacAddress {} and Identifier {}",
553 supplicantCp.deviceId(), supplicantCp.port(), dstMac, radiusPacket.getIdentifier() & 0xff);
Andrea Campanellac4781e62020-10-08 12:58:45 +0200554 RADIUSAttribute radiusAttrState = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE);
555 byte[] challengeState = null;
556 if (radiusAttrState != null) {
557 challengeState = radiusAttrState.getValue();
558 }
559 try {
560 eapPayload = radiusPacket.decapsulateMessage();
561 eth = buildEapolResponse(stateMachine.supplicantAddress(),
562 MacAddress.valueOf(nasMacAddress),
563 stateMachine.vlanId(),
564 EAPOL.EAPOL_PACKET,
565 eapPayload, stateMachine.priorityCode());
566 stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState);
567 } catch (DeserializationException e) {
568 log.error(e.getMessage());
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700569 break;
Andrea Campanellac4781e62020-10-08 12:58:45 +0200570 }
Matteo Scandoloe033c262020-10-14 11:37:39 -0700571 log.debug("Send EAP challenge response to supplicant on dev/port: {}/{}" +
572 " with MacAddress {} and Identifier {}",
573 supplicantCp.deviceId(), supplicantCp.port(), dstMac, radiusPacket.getIdentifier() & 0xff);
Andrea Campanellac4781e62020-10-08 12:58:45 +0200574 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint(), true);
575 aaaStatisticsManager.getAaaStats().increaseChallengeResponsesRx();
576 outPacketSupp.add(eapPayload.getIdentifier());
Andrea Campanella76ae68d2020-10-14 11:16:37 +0200577 aaaStatisticsManager.getAaaStats().incrementPendingReqSupp();
Andrea Campanellac4781e62020-10-08 12:58:45 +0200578 //increasing packets send to server
579 machineStats.incrementTotalPacketsSent();
580 machineStats.incrementTotalOctetSent(eapPayload.getLength());
581 break;
582 case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
Matteo Scandoloe033c262020-10-14 11:37:39 -0700583 log.debug("RADIUS packet: RADIUS_CODE_ACCESS_ACCEPT for dev/port: {}/{}" +
584 " with MacAddress {} and Identifier {}",
585 supplicantCp.deviceId(), supplicantCp.port(), dstMac, radiusPacket.getIdentifier() & 0xff);
Andrea Campanellac4781e62020-10-08 12:58:45 +0200586 //send an EAPOL - Success to the supplicant.
587 byte[] eapMessageSuccess =
588 radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
589 try {
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700590 eapPayload = EAP.deserializer().deserialize(
591 eapMessageSuccess, 0, eapMessageSuccess.length);
Andrea Campanellac4781e62020-10-08 12:58:45 +0200592 } catch (DeserializationException e) {
593 log.error(e.getMessage());
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700594 break;
Andrea Campanellac4781e62020-10-08 12:58:45 +0200595 }
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700596
Andrea Campanellac4781e62020-10-08 12:58:45 +0200597 eth = buildEapolResponse(stateMachine.supplicantAddress(),
598 MacAddress.valueOf(nasMacAddress),
599 stateMachine.vlanId(),
600 EAPOL.EAPOL_PACKET,
601 eapPayload, stateMachine.priorityCode());
Matteo Scandoloe033c262020-10-14 11:37:39 -0700602 log.info("Send EAP success message to supplicant on dev/port: {}/{}" +
603 " with MacAddress {} and Identifier {}",
604 supplicantCp.deviceId(), supplicantCp.port(), dstMac, radiusPacket.getIdentifier() & 0xff);
Andrea Campanellac4781e62020-10-08 12:58:45 +0200605 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint(), false);
606 aaaStatisticsManager.getAaaStats().incrementEapolAuthSuccessTrans();
607
608 stateMachine.authorizeAccess();
609 aaaStatisticsManager.getAaaStats().increaseAcceptResponsesRx();
610 //increasing packets send to server
611 machineStats.incrementTotalPacketsSent();
612 machineStats.incrementTotalOctetSent(eapPayload.getLength());
613 break;
614 case RADIUS.RADIUS_CODE_ACCESS_REJECT:
Matteo Scandoloe033c262020-10-14 11:37:39 -0700615 log.debug("RADIUS packet: RADIUS_CODE_ACCESS_REJECT for dev/port: {}/{}" +
616 " with MacAddress {} and Identifier {}",
617 supplicantCp.deviceId(), supplicantCp.port(), dstMac, radiusPacket.getIdentifier() & 0xff);
Andrea Campanellac4781e62020-10-08 12:58:45 +0200618 //send an EAPOL - Failure to the supplicant.
619 byte[] eapMessageFailure;
620 eapPayload = new EAP();
621 RADIUSAttribute radiusAttrEap = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE);
622 if (radiusAttrEap == null) {
623 eapPayload.setCode(EAP.FAILURE);
624 eapPayload.setIdentifier(stateMachine.challengeIdentifier());
625 eapPayload.setLength(EAP.EAP_HDR_LEN_SUC_FAIL);
626 } else {
627 eapMessageFailure = radiusAttrEap.getValue();
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700628 try {
Andrea Campanellac4781e62020-10-08 12:58:45 +0200629 eapPayload = EAP.deserializer().deserialize(
630 eapMessageFailure, 0, eapMessageFailure.length);
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700631 } catch (DeserializationException e) {
632 log.error(e.getMessage());
633 break;
634 }
Andrea Campanellac4781e62020-10-08 12:58:45 +0200635 }
636 eth = buildEapolResponse(stateMachine.supplicantAddress(),
637 MacAddress.valueOf(nasMacAddress),
638 stateMachine.vlanId(),
639 EAPOL.EAPOL_PACKET,
640 eapPayload, stateMachine.priorityCode());
Matteo Scandoloe033c262020-10-14 11:37:39 -0700641 log.warn("Send EAP failure message to supplicant {} on dev/port: {}/{}" +
642 " with MacAddress {} and Identifier {}", supplicantCp.deviceId(), supplicantCp.port(),
643 dstMac, stateMachine.challengeIdentifier() & 0xff);
Andrea Campanellac4781e62020-10-08 12:58:45 +0200644 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint(), false);
645 aaaStatisticsManager.getAaaStats().incrementEapolauthFailureTrans();
646
647 stateMachine.denyAccess();
648 aaaStatisticsManager.getAaaStats().increaseRejectResponsesRx();
649 //increasing packets send to server
650 machineStats.incrementTotalPacketsSent();
651 machineStats.incrementTotalOctetSent(eapPayload.getLength());
652 //pushing machine stats to kafka
653 AaaSupplicantMachineStats machineObj = aaaSupplicantStatsManager.getSupplicantStats(machineStats);
654 aaaSupplicantStatsManager.getMachineStatsDelegate()
655 .notify(new AaaMachineStatisticsEvent(AaaMachineStatisticsEvent.Type.STATS_UPDATE,
656 machineObj));
657 break;
658 default:
Matteo Scandoloe033c262020-10-14 11:37:39 -0700659 log.warn("Unknown RADIUS message received with code: {} for dev/port: {}/{}" +
660 " with MacAddress {} and Identifier {}",
661 radiusPacket.getCode(), supplicantCp.deviceId(), supplicantCp.port(), dstMac,
662 radiusPacket.getIdentifier() & 0xff);
Andrea Campanellac4781e62020-10-08 12:58:45 +0200663 aaaStatisticsManager.getAaaStats().increaseUnknownTypeRx();
664 //increasing packets received to server
665 machineStats.incrementTotalPacketsReceived();
666 try {
667 machineStats.incrementTotalOctetReceived(radiusPacket.decapsulateMessage().getLength());
668 } catch (DeserializationException e) {
669 log.error(e.getMessage());
670 break;
671 }
672 }
673 aaaStatisticsManager.getAaaStats().countDroppedResponsesRx();
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700674 }
675
Ray Milkey967776a2015-10-07 14:37:17 -0700676 /**
677 * Send the ethernet packet to the supplicant.
678 *
679 * @param ethernetPkt the ethernet packet
680 * @param connectPoint the connect point to send out
681 */
Shubham Sharma1f193582019-07-11 12:12:41 +0000682 private void sendPacketToSupplicant(Ethernet ethernetPkt, ConnectPoint connectPoint, boolean isChallengeResponse) {
Ray Milkey967776a2015-10-07 14:37:17 -0700683 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
684 OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(),
685 treatment, ByteBuffer.wrap(ethernetPkt.serialize()));
Shubham Sharma1f193582019-07-11 12:12:41 +0000686 EAPOL eap = ((EAPOL) ethernetPkt.getPayload());
Saurav Das987441a2018-09-18 16:33:47 -0700687 if (log.isTraceEnabled()) {
Andrea Campanellac4781e62020-10-08 12:58:45 +0200688 log.trace("Sending eapol payload {} enclosed in {} to supplicant at {} with MacAddress {}",
689 eap, ethernetPkt, connectPoint, ethernetPkt.getDestinationMAC());
Saurav Das987441a2018-09-18 16:33:47 -0700690 }
Ray Milkey967776a2015-10-07 14:37:17 -0700691 packetService.emit(packet);
Shubham Sharma1f193582019-07-11 12:12:41 +0000692 if (isChallengeResponse) {
693 aaaStatisticsManager.getAaaStats().incrementEapPktTxauthEap();
694 }
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000695 aaaStatisticsManager.getAaaStats().incrementEapolFramesTx();
696 aaaStatisticsManager.getAaaStats().countReqEapFramesTx();
Ray Milkey967776a2015-10-07 14:37:17 -0700697 }
698
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400699 @Override
700 public String toString() {
701 return ToStringBuilder.reflectionToString(this);
702 }
703
Jonathan Hart612651f2019-11-25 09:21:43 -0800704 @Override
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800705 public Iterable<AuthenticationRecord> getAuthenticationRecords() {
Hardik Windlassd0b49692020-02-26 18:17:14 +0000706 return authentications.values();
Jonathan Hart612651f2019-11-25 09:21:43 -0800707 }
708
709 @Override
710 public boolean removeAuthenticationStateByMac(MacAddress mac) {
711
Hardik Windlassd0b49692020-02-26 18:17:14 +0000712 Optional<AuthenticationRecord> r = authentications.values().stream()
713 .filter(v -> v.supplicantAddress().equals(mac))
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800714 .findFirst();
Jonathan Hart612651f2019-11-25 09:21:43 -0800715
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800716 if (r.isEmpty()) {
717 return false;
Jonathan Hart612651f2019-11-25 09:21:43 -0800718 }
719
Hardik Windlassd0b49692020-02-26 18:17:14 +0000720 AuthenticationRecord removed =
721 authentications.remove(r.get().supplicantConnectPoint());
Jonathan Hart612651f2019-11-25 09:21:43 -0800722
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800723 return removed != null;
Jonathan Hart612651f2019-11-25 09:21:43 -0800724 }
725
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800726 StateMachine getStateMachine(String sessionId) {
Jonathan Hart612651f2019-11-25 09:21:43 -0800727 return stateMachines.get(sessionId);
728 }
729
730 private String sessionId(ConnectPoint cp) {
731 return cp.deviceId().toString() + cp.port().toString();
732 }
733
Ari Saha89831742015-06-26 10:31:48 -0700734 // our handler defined as a private inner class
735
736 /**
737 * Packet processor responsible for forwarding packets along their paths.
738 */
739 private class ReactivePacketProcessor implements PacketProcessor {
740 @Override
741 public void process(PacketContext context) {
Andrea Campanellac4781e62020-10-08 12:58:45 +0200742 packetProcessorExecutor.execute(() -> {
743 // Extract the original Ethernet frame from the packet information
744 InboundPacket pkt = context.inPacket();
Matteo Scandoloe033c262020-10-14 11:37:39 -0700745 if (pkt == null) {
746 log.error("InboundPacket is null when parsed from {}", context);
747 return;
748 }
Andrea Campanellac4781e62020-10-08 12:58:45 +0200749 Ethernet ethPkt = pkt.parsed();
750 if (ethPkt == null) {
Matteo Scandoloe033c262020-10-14 11:37:39 -0700751 log.error("EthPkt is null when parsed from {}", pkt);
Andrea Campanellac4781e62020-10-08 12:58:45 +0200752 return;
753 }
Ari Saha89831742015-06-26 10:31:48 -0700754
Andrea Campanellac4781e62020-10-08 12:58:45 +0200755 // identify if incoming packet comes from supplicant (EAP) or RADIUS
756 switch (EthType.EtherType.lookup(ethPkt.getEtherType())) {
757 case EAPOL:
Matteo Scandoloe033c262020-10-14 11:37:39 -0700758 if (log.isTraceEnabled()) {
759 log.trace("Received EAPOL supplicant packet from dev/port: {} with MacAddress {}",
760 context.inPacket().receivedFrom(), ethPkt.getSourceMAC());
761 }
Andrea Campanellac4781e62020-10-08 12:58:45 +0200762 handleSupplicantPacket(context.inPacket());
763 break;
764 default:
Matteo Scandoloe033c262020-10-14 11:37:39 -0700765 if (log.isTraceEnabled()) {
766 log.trace("Received packet-in from RADIUS server {} in enclosing packet {} from "
767 + "dev/port: {} with MacAddress {}", ethPkt, context.inPacket(),
768 context.inPacket().receivedFrom(), ethPkt.getSourceMAC());
769 }
Andrea Campanellac4781e62020-10-08 12:58:45 +0200770 // any other packets let the specific implementation handle
771 impl.handlePacketFromServer(context);
772 }
773 });
Ari Saha89831742015-06-26 10:31:48 -0700774 }
775
Ray Milkey9eb293f2015-09-30 15:09:17 -0700776 /**
777 * Creates and initializes common fields of a RADIUS packet.
778 *
Ray Milkey967776a2015-10-07 14:37:17 -0700779 * @param stateMachine state machine for the request
Matteo Scandoloe033c262020-10-14 11:37:39 -0700780 * @param eapPacket EAP packet
Ray Milkey9eb293f2015-09-30 15:09:17 -0700781 * @return RADIUS packet
782 */
Ray Milkey967776a2015-10-07 14:37:17 -0700783 private RADIUS getRadiusPayload(StateMachine stateMachine, byte identifier, EAP eapPacket) {
Ray Milkey9eb293f2015-09-30 15:09:17 -0700784 RADIUS radiusPayload =
785 new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
786 eapPacket.getIdentifier());
Ray Milkey967776a2015-10-07 14:37:17 -0700787
788 // set Request Authenticator in StateMachine
789 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
790
Ray Milkey9eb293f2015-09-30 15:09:17 -0700791 radiusPayload.setIdentifier(identifier);
792 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
Ray Milkey967776a2015-10-07 14:37:17 -0700793 stateMachine.username());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700794
795 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
Matteo Scandoloe033c262020-10-14 11:37:39 -0700796 AaaManager.this.nasIpAddress.getAddress());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700797
798 radiusPayload.encapsulateMessage(eapPacket);
Ray Milkey9eb293f2015-09-30 15:09:17 -0700799
800 return radiusPayload;
801 }
Ari Saha89831742015-06-26 10:31:48 -0700802
803 /**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700804 * Handles PAE packets (supplicant).
805 *
806 * @param inPacket Ethernet packet coming from the supplicant
Ari Saha89831742015-06-26 10:31:48 -0700807 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800808 private void handleSupplicantPacket(InboundPacket inPacket) {
Matteo Scandoloe033c262020-10-14 11:37:39 -0700809
Jonathan Harta46dddf2015-06-30 15:31:20 -0700810 Ethernet ethPkt = inPacket.parsed();
Ari Saha89831742015-06-26 10:31:48 -0700811 // Where does it come from?
Jonathan Hart092dfb22015-11-16 23:05:21 -0800812 MacAddress srcMac = ethPkt.getSourceMAC();
Ari Saha89831742015-06-26 10:31:48 -0700813
Jonathan Harta46dddf2015-06-30 15:31:20 -0700814 DeviceId deviceId = inPacket.receivedFrom().deviceId();
815 PortNumber portNumber = inPacket.receivedFrom().port();
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800816 String sessionId = sessionId(inPacket.receivedFrom());
Saurav Das987441a2018-09-18 16:33:47 -0700817 EAPOL eapol = (EAPOL) ethPkt.getPayload();
Matteo Scandoloe033c262020-10-14 11:37:39 -0700818
Saurav Das987441a2018-09-18 16:33:47 -0700819 if (log.isTraceEnabled()) {
820 log.trace("Received EAPOL packet {} in enclosing packet {} from "
Matteo Scandoloe033c262020-10-14 11:37:39 -0700821 + "dev/port: {}/{} with MacAddress {} and type {}",
822 eapol, ethPkt, deviceId, portNumber, srcMac, eapol.getEapolType());
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100823 }
Jonathan Harta46dddf2015-06-30 15:31:20 -0700824
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000825 short pktlen = eapol.getPacketLength();
826 byte[] eapPayLoadBuffer = eapol.serialize();
827 int len = eapPayLoadBuffer.length;
828 if (len != (HEADER_LENGTH + pktlen)) {
Matteo Scandoloe033c262020-10-14 11:37:39 -0700829 log.error("Invalid EAPOL pkt length {} (shoudl be {}) for packet {} from dev/port: {}/{} " +
830 "with MacAddress {}", len, HEADER_LENGTH + pktlen, eapol, deviceId, portNumber, srcMac);
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000831 aaaStatisticsManager.getAaaStats().incrementInvalidBodyLength();
832 return;
833 }
834 if (!VALID_EAPOL_TYPE.contains(eapol.getEapolType())) {
Matteo Scandoloe033c262020-10-14 11:37:39 -0700835 log.error("Invalid EAPOL Type {} for packet {} from dev/port: {}/{} with MacAddress {}",
836 eapol.getEapolType(), eapol, deviceId, portNumber, srcMac);
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000837 aaaStatisticsManager.getAaaStats().incrementInvalidPktType();
838 return;
839 }
840 if (pktlen >= 0 && ethPkt.getEtherType() == EthType.EtherType.EAPOL.ethType().toShort()) {
841 aaaStatisticsManager.getAaaStats().incrementValidEapolFramesRx();
842 }
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700843 StateMachine stateMachine = stateMachines.computeIfAbsent(sessionId, id ->
844 new StateMachine(id, serverStatusAndStateMachineTimeoutExecutor));
Jonathan Hart612651f2019-11-25 09:21:43 -0800845 stateMachine.setEapolTypeVal(eapol.getEapolType());
Saurav Das987441a2018-09-18 16:33:47 -0700846
Ari Saha89831742015-06-26 10:31:48 -0700847 switch (eapol.getEapolType()) {
848 case EAPOL.EAPOL_START:
Andrea Campanellac4781e62020-10-08 12:58:45 +0200849 log.debug("EAP packet: EAPOL_START from dev/port: {}/{} with MacAddress {}",
850 deviceId, portNumber, srcMac);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700851 stateMachine.setSupplicantConnectpoint(inPacket.receivedFrom());
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800852 stateMachine.setSupplicantAddress(srcMac);
Jonathan Hart5db44532018-07-12 18:13:54 -0700853 stateMachine.start();
Jonathan Hart612651f2019-11-25 09:21:43 -0800854
Andrea Campanella76ae68d2020-10-14 11:16:37 +0200855 aaaStatisticsManager.getAaaStats().incrementEapolStartReqRx();
Ray Milkeyf51eba22015-09-25 10:24:23 -0700856 //send an EAP Request/Identify to the supplicant
857 EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.identifier(), EAP.ATTR_IDENTITY, null);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100858 if (ethPkt.getVlanID() != Ethernet.VLAN_UNTAGGED) {
Matteo Scandoloe033c262020-10-14 11:37:39 -0700859 stateMachine.setPriorityCode(ethPkt.getPriorityCode());
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100860 }
Jonathan Hart092dfb22015-11-16 23:05:21 -0800861 Ethernet eth = buildEapolResponse(srcMac, MacAddress.valueOf(nasMacAddress),
Matteo Scandoloe033c262020-10-14 11:37:39 -0700862 ethPkt.getVlanID(), EAPOL.EAPOL_PACKET, eapPayload, stateMachine.priorityCode());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400863
Ray Milkeyf51eba22015-09-25 10:24:23 -0700864 stateMachine.setVlanId(ethPkt.getVlanID());
Matteo Scandoloe033c262020-10-14 11:37:39 -0700865 log.debug("Getting EAP identity from supplicant {} and Identifier {}",
866 stateMachine.supplicantAddress().toString(), stateMachine.identifier() & 0xff);
Shubham Sharma1f193582019-07-11 12:12:41 +0000867 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint(), false);
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000868 aaaStatisticsManager.getAaaStats().incrementRequestIdFramesTx();
Ari Saha89831742015-06-26 10:31:48 -0700869 break;
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800870 case EAPOL.EAPOL_LOGOFF:
Andrea Campanellac4781e62020-10-08 12:58:45 +0200871 log.debug("EAP packet: EAPOL_LOGOFF from dev/port: {}/{} with MacAddress {}",
872 deviceId, portNumber, srcMac);
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +0000873 //posting the machine stat data for current supplicant device.
874 if (stateMachine.getSessionTerminateReason() == null ||
875 stateMachine.getSessionTerminateReason().equals("")) {
876 stateMachine.setSessionTerminateReason(
877 StateMachine.SessionTerminationReasons.SUPPLICANT_LOGOFF.getReason());
878 }
879 AaaSupplicantMachineStats obj = aaaSupplicantStatsManager.getSupplicantStats(stateMachine);
880 aaaSupplicantStatsManager.getMachineStatsDelegate()
881 .notify(new AaaMachineStatisticsEvent(AaaMachineStatisticsEvent.Type.STATS_UPDATE, obj));
Ray Milkeyb34b4962016-01-04 10:24:43 -0800882 if (stateMachine.state() == StateMachine.STATE_AUTHORIZED) {
883 stateMachine.logoff();
Shubham Sharma1f193582019-07-11 12:12:41 +0000884 aaaStatisticsManager.getAaaStats().incrementEapolLogoffRx();
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800885 }
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000886 if (stateMachine.state() == StateMachine.STATE_IDLE) {
887 aaaStatisticsManager.getAaaStats().incrementAuthStateIdle();
888 }
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800889 break;
Ari Saha89831742015-06-26 10:31:48 -0700890 case EAPOL.EAPOL_PACKET:
Matteo Scandoloe033c262020-10-14 11:37:39 -0700891
Ray Milkey9eb293f2015-09-30 15:09:17 -0700892 // check if this is a Response/Identify or a Response/TLS
Ari Saha89831742015-06-26 10:31:48 -0700893 EAP eapPacket = (EAP) eapol.getPayload();
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000894 Byte identifier = new Byte(eapPacket.getIdentifier());
Matteo Scandoloe033c262020-10-14 11:37:39 -0700895 log.debug("EAP packet: EAPOL_PACKET from dev/port: {}/{} with MacAddress {} with Identifier {}",
896 deviceId, portNumber, srcMac, identifier.doubleValue());
Jonathan Hart612651f2019-11-25 09:21:43 -0800897 // get identifier for request and store mapping to session ID
898 RequestIdentifier radiusIdentifier = idManager.getNewIdentifier(sessionId);
Matteo Scandoloe033c262020-10-14 11:37:39 -0700899 if (radiusIdentifier == null) {
900 log.error("Cannot get RADIUS Identifier, dropping packet");
901 return;
902 }
Jonathan Hart612651f2019-11-25 09:21:43 -0800903
Ari Saha89831742015-06-26 10:31:48 -0700904 byte dataType = eapPacket.getDataType();
Matteo Scandoloe033c262020-10-14 11:37:39 -0700905
Ari Saha89831742015-06-26 10:31:48 -0700906 switch (dataType) {
Ray Milkey9eb293f2015-09-30 15:09:17 -0700907 case EAP.ATTR_IDENTITY:
Matteo Scandoloe033c262020-10-14 11:37:39 -0700908 handleAttrIdentity(inPacket, srcMac, deviceId, portNumber,
909 eapol, stateMachine, eapPacket, radiusIdentifier);
Ray Milkey9eb293f2015-09-30 15:09:17 -0700910 break;
Ari Saha89831742015-06-26 10:31:48 -0700911 case EAP.ATTR_MD5:
Matteo Scandoloe033c262020-10-14 11:37:39 -0700912 handleMD5(inPacket, srcMac, deviceId, portNumber, stateMachine,
913 eapPacket, identifier, radiusIdentifier);
Ari Saha89831742015-06-26 10:31:48 -0700914 break;
915 case EAP.ATTR_TLS:
Matteo Scandoloe033c262020-10-14 11:37:39 -0700916 handleTls(inPacket, srcMac, deviceId, portNumber, stateMachine,
917 eapPacket, identifier, radiusIdentifier);
Ari Saha89831742015-06-26 10:31:48 -0700918 break;
919 default:
Matteo Scandoloe033c262020-10-14 11:37:39 -0700920 log.warn("Unknown EAP packet type from dev/port: {}/{} with MacAddress {} and " +
921 "Identifier {}", deviceId, portNumber, srcMac, eapPacket.getIdentifier() & 0xff);
Ari Saha89831742015-06-26 10:31:48 -0700922 return;
923 }
924 break;
925 default:
Andrea Campanellac4781e62020-10-08 12:58:45 +0200926 log.debug("Skipping EAPOL message {} from dev/port: {}/{} with MacAddress {}",
927 eapol.getEapolType(), deviceId, portNumber, srcMac);
Ari Saha89831742015-06-26 10:31:48 -0700928 }
Shubham Sharma1f193582019-07-11 12:12:41 +0000929 aaaStatisticsManager.getAaaStats().countTransRespNotNak();
930 aaaStatisticsManager.getAaaStats().countEapolResIdentityMsgTrans();
Ari Saha89831742015-06-26 10:31:48 -0700931 }
Matteo Scandoloe033c262020-10-14 11:37:39 -0700932
933 private void handleAttrIdentity(InboundPacket inPacket, MacAddress srcMac, DeviceId deviceId,
934 PortNumber portNumber, EAPOL eapol, StateMachine stateMachine,
935 EAP eapPacket, RequestIdentifier radiusIdentifier) {
936 RADIUS radiusPayload;
937 log.debug("EAP packet: EAPOL_PACKET ATTR_IDENTITY from dev/port: {}/{} with MacAddress {}" +
938 " and Identifier {}", deviceId, portNumber, srcMac, eapPacket.getIdentifier() & 0xff);
939 //Setting the time of this response from RG, only when its not a re-transmission.
940 if (stateMachine.getLastPacketReceivedTime() == 0) {
941 stateMachine.setLastPacketReceivedTime(System.currentTimeMillis());
942 }
943 // request id access to RADIUS
944 stateMachine.setUsername(eapPacket.getData());
945
946 radiusPayload = getRadiusPayload(stateMachine, radiusIdentifier.identifier(), eapPacket);
947 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
948 radiusPayload.addMessageAuthenticator(radiusSecret);
949
950 if (log.isTraceEnabled()) {
951 log.trace("Sending ATTR_IDENTITY packet to RADIUS for supplicant at dev/port: " +
952 "{}/{} with MacAddress {} and Identifier {}", deviceId, portNumber,
953 srcMac, radiusIdentifier.identifier() & 0xff);
954 }
955
956 sendRadiusPacket(radiusPayload, inPacket);
957 stateMachine.setWaitingForRadiusResponse(true);
958 aaaStatisticsManager.getAaaStats().incrementRadiusReqIdTx();
959 aaaStatisticsManager.getAaaStats().incrementEapolAtrrIdentity();
960 // change the state to "PENDING"
961 if (stateMachine.state() == StateMachine.STATE_PENDING) {
962 aaaStatisticsManager.getAaaStats().increaseRequestReTx();
963 stateMachine.incrementTotalPacketsSent();
964 stateMachine.incrementTotalOctetSent(eapol.getPacketLength());
965 }
966 stateMachine.requestAccess();
967 }
968
969 private void handleMD5(InboundPacket inPacket, MacAddress srcMac, DeviceId deviceId,
970 PortNumber portNumber, StateMachine stateMachine, EAP eapPacket,
971 Byte identifier, RequestIdentifier radiusIdentifier) {
972 RADIUS radiusPayload;
973 log.debug("EAP packet: EAPOL_PACKET ATTR_MD5 from dev/port: {}/{} with MacAddress {}" +
974 " and Identifier {}", deviceId, portNumber, srcMac, eapPacket.getIdentifier() & 0xff);
975 // verify if the EAP identifier corresponds to the
976 // challenge identifier from the client state
977 // machine.
978 stateMachine.setLastPacketReceivedTime(System.currentTimeMillis());
979 if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) {
980 //send the RADIUS challenge response
981 radiusPayload = getRadiusPayload(stateMachine,
982 radiusIdentifier.identifier(), eapPacket);
983 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
984
985 if (stateMachine.challengeState() != null) {
986 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
987 stateMachine.challengeState());
988 }
989 radiusPayload.addMessageAuthenticator(radiusSecret);
990 if (outPacketSupp.contains(eapPacket.getIdentifier())) {
991 aaaStatisticsManager.getAaaStats().decrementPendingReqSupp();
992 outPacketSupp.remove(identifier);
993 }
994 if (log.isTraceEnabled()) {
995 log.trace("Sending ATTR_MD5 packet to RADIUS for supplicant at dev/port: {}/{}" +
996 " with MacAddress {} and Identifier {}", deviceId, portNumber, srcMac,
997 radiusIdentifier.identifier() & 0xff);
998 }
999 sendRadiusPacket(radiusPayload, inPacket);
1000 stateMachine.setWaitingForRadiusResponse(true);
1001 aaaStatisticsManager.getAaaStats().incrementRadiusReqChallengeTx();
1002 aaaStatisticsManager.getAaaStats().incrementEapolMd5RspChall();
1003 } else {
1004 log.error("eapolIdentifier {} and stateMachine Identifier {} do not " +
1005 "correspond for packet from dev/port: {}/{} with MacAddress {}",
1006 eapPacket.getIdentifier() & 0xff, stateMachine.challengeIdentifier() & 0xff,
1007 deviceId, portNumber, srcMac);
1008 aaaStatisticsManager.getAaaStats().incrementEapolMd5RspChall();
1009 if (outPacketSupp.contains(eapPacket.getIdentifier())) {
1010 aaaStatisticsManager.getAaaStats().decrementPendingReqSupp();
1011 outPacketSupp.remove(identifier);
1012 }
1013 aaaStatisticsManager.getAaaStats().incrementEapolauthFailureTrans();
1014 }
1015 }
1016
1017
1018 private void handleTls(InboundPacket inPacket, MacAddress srcMac, DeviceId deviceId,
1019 PortNumber portNumber, StateMachine stateMachine, EAP eapPacket,
1020 Byte identifier, RequestIdentifier radiusIdentifier) {
1021 RADIUS radiusPayload;
1022 log.debug("EAP packet: EAPOL_PACKET ATTR_TLS from dev/port: {}/{} with MacAddress {} " +
1023 "and Identifier {}", deviceId, portNumber, srcMac, eapPacket.getIdentifier() & 0xff);
1024 // request id access to RADIUS
1025 radiusPayload = getRadiusPayload(stateMachine, radiusIdentifier.identifier(), eapPacket);
1026 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
1027 if (stateMachine.challengeState() != null) {
1028 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
1029 stateMachine.challengeState());
1030 }
1031 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
1032 radiusPayload.addMessageAuthenticator(radiusSecret);
1033 if (outPacketSupp.contains(eapPacket.getIdentifier())) {
1034 aaaStatisticsManager.getAaaStats().decrementPendingReqSupp();
1035 outPacketSupp.remove(identifier);
1036 }
1037 if (log.isTraceEnabled()) {
1038 log.trace("Sending ATTR_TLS packet to RADIUS for supplicant at dev/port: {}/{} with " +
1039 "MacAddress {} and Identifier {}", deviceId, portNumber, srcMac,
1040 radiusIdentifier.identifier() & 0xff);
1041 }
1042 sendRadiusPacket(radiusPayload, inPacket);
1043 stateMachine.setWaitingForRadiusResponse(true);
1044 aaaStatisticsManager.getAaaStats().incrementRadiusReqChallengeTx();
1045 aaaStatisticsManager.getAaaStats().incrementEapolTlsRespChall();
1046 if (stateMachine.state() != StateMachine.STATE_PENDING) {
1047 stateMachine.requestAccess();
1048 }
1049 }
Ray Milkey967776a2015-10-07 14:37:17 -07001050 }
1051
Amit Ghoshc9ac1e52017-07-28 12:31:18 +01001052 /**
Jonathan Hart5db44532018-07-12 18:13:54 -07001053 * Delegate allowing the StateMachine to notify us of events.
1054 */
1055 private class InternalStateMachineDelegate implements StateMachineDelegate {
1056
1057 @Override
1058 public void notify(AuthenticationEvent authenticationEvent) {
1059 log.info("Auth event {} for {}",
Matteo Scandoloe033c262020-10-14 11:37:39 -07001060 authenticationEvent.type(), authenticationEvent.subject());
Jonathan Hart612651f2019-11-25 09:21:43 -08001061
1062 if (authenticationEvent.type() == AuthenticationEvent.Type.TIMEOUT) {
1063 handleStateMachineTimeout(authenticationEvent.subject());
1064 }
1065
Jonathan Hart9d1ce802020-01-28 10:45:08 -08001066 AuthenticationRecord record = authenticationEvent.authenticationRecord();
1067 if (record == null) {
1068 authentications.remove(authenticationEvent.subject());
1069 } else {
1070 authentications.put(authenticationEvent.subject(), record);
1071 }
1072
Jonathan Hart5db44532018-07-12 18:13:54 -07001073 post(authenticationEvent);
1074 }
1075 }
1076
Jonathan Hart612651f2019-11-25 09:21:43 -08001077 private void handleStateMachineTimeout(ConnectPoint supplicantConnectPoint) {
1078 StateMachine stateMachine = stateMachines.remove(sessionId(supplicantConnectPoint));
Andrea Campanellae66466a2020-02-03 14:05:45 +00001079 //pushing captured machine stats to kafka
1080 stateMachine.setSessionTerminateReason("Time out");
1081 AaaSupplicantMachineStats obj = aaaSupplicantStatsManager
1082 .getSupplicantStats(stateMachine);
1083 aaaSupplicantStatsManager.getMachineStatsDelegate()
1084 .notify(new AaaMachineStatisticsEvent(
1085 AaaMachineStatisticsEvent.Type.STATS_UPDATE, obj));
1086
Jonathan Hart612651f2019-11-25 09:21:43 -08001087 if (stateMachine.state() == StateMachine.STATE_PENDING && stateMachine.isWaitingForRadiusResponse()) {
1088 aaaStatisticsManager.getAaaStats().increaseTimedOutPackets();
1089 }
1090
1091 StateMachine.deleteStateMachineMapping(stateMachine);
1092 }
1093
Jonathan Hart5db44532018-07-12 18:13:54 -07001094 /**
Amit Ghoshc9ac1e52017-07-28 12:31:18 +01001095 * Configuration Listener, handles change in configuration.
1096 */
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001097 private class InternalConfigListener implements NetworkConfigListener {
1098
1099 /**
Ray Milkeyc9e8dcc2015-12-30 10:31:32 -08001100 * Reconfigures the AAA application according to the
1101 * configuration parameters passed.
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001102 *
1103 * @param cfg configuration object
1104 */
Jonathan Hart092dfb22015-11-16 23:05:21 -08001105 private void reconfigureNetwork(AaaConfig cfg) {
Matt Jeanneret2ff1a782018-06-13 15:24:25 -04001106 log.info("Reconfiguring AaaConfig from config: {}", cfg);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +01001107
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001108 if (cfg == null) {
Jonathan Hart092dfb22015-11-16 23:05:21 -08001109 newCfg = new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001110 } else {
1111 newCfg = cfg;
1112 }
1113 if (newCfg.nasIp() != null) {
1114 nasIpAddress = newCfg.nasIp();
1115 }
1116 if (newCfg.radiusIp() != null) {
1117 radiusIpAddress = newCfg.radiusIp();
1118 }
1119 if (newCfg.radiusMac() != null) {
1120 radiusMacAddress = newCfg.radiusMac();
1121 }
1122 if (newCfg.nasMac() != null) {
1123 nasMacAddress = newCfg.nasMac();
1124 }
Andrea Campanellac4781e62020-10-08 12:58:45 +02001125 if (newCfg.radiusSecret() != null && !newCfg.radiusSecret().equals(radiusSecret)) {
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001126 radiusSecret = newCfg.radiusSecret();
Andrea Campanellac4781e62020-10-08 12:58:45 +02001127 radiusOperationalStatusService.initialize(nasIpAddress.getAddress(), radiusSecret, impl);
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001128 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +01001129
Deepa Vaddireddye0e10722017-09-27 05:00:10 +05301130 boolean reconfigureCustomizer = false;
1131 if (customizer == null || !customizer.equals(newCfg.radiusPktCustomizer())) {
1132 customizer = newCfg.radiusPktCustomizer();
1133 configurePacketCustomizer();
1134 reconfigureCustomizer = true;
1135 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +01001136
Deepa Vaddireddye0e10722017-09-27 05:00:10 +05301137 if (radiusConnectionType == null
1138 || reconfigureCustomizer
1139 || !radiusConnectionType.equals(newCfg.radiusConnectionType())) {
1140 radiusConnectionType = newCfg.radiusConnectionType();
1141 if (impl != null) {
1142 impl.withdrawIntercepts();
1143 impl.clearLocalState();
1144 }
1145 configureRadiusCommunication();
1146 impl.initializeLocalState(newCfg);
1147 impl.requestIntercepts();
1148 } else if (impl != null) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +01001149 impl.clearLocalState();
1150 impl.initializeLocalState(newCfg);
Ray Milkey5d99bd12015-10-06 15:41:30 -07001151 }
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001152 }
1153
1154 @Override
1155 public void event(NetworkConfigEvent event) {
1156
1157 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
1158 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
Jonathan Hart092dfb22015-11-16 23:05:21 -08001159 event.configClass().equals(AaaConfig.class)) {
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001160
Jonathan Hart092dfb22015-11-16 23:05:21 -08001161 AaaConfig cfg = netCfgService.getConfig(appId, AaaConfig.class);
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001162 reconfigureNetwork(cfg);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +01001163
Matt Jeanneret2ff1a782018-06-13 15:24:25 -04001164 log.info("Reconfigured: {}", cfg.toString());
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001165 }
1166 }
1167 }
Amit Ghoshf739be52017-09-21 15:49:37 +01001168
Jonathan Hart9d1ce802020-01-28 10:45:08 -08001169 private class InternalMapEventListener implements MapEventListener<ConnectPoint, AuthenticationRecord> {
1170 @Override
1171 public void event(MapEvent<ConnectPoint, AuthenticationRecord> event) {
1172 if (event.type() == MapEvent.Type.REMOVE) {
1173 // remove local state machine if user has requested remove
1174 StateMachine sm = stateMachines.remove(sessionId(event.key()));
1175 if (sm != null) {
1176 sm.stop();
1177 }
1178 }
1179 }
1180 }
1181
Amit Ghoshf739be52017-09-21 15:49:37 +01001182 private class InternalDeviceListener implements DeviceListener {
1183 @Override
1184 public void event(DeviceEvent event) {
Andrea Campanellabba33672020-02-11 14:03:01 +01001185 DeviceId deviceId = event.subject().id();
Amit Ghoshf739be52017-09-21 15:49:37 +01001186 switch (event.type()) {
1187 case PORT_REMOVED:
Amit Ghoshf739be52017-09-21 15:49:37 +01001188 PortNumber portNumber = event.port().number();
Andrea Campanellabba33672020-02-11 14:03:01 +01001189 String sessionId = deviceId.toString() + portNumber.toString();
Girish Kumar064084c2020-02-04 08:32:46 +00001190 log.debug("Received PORT_REMOVED event. Clearing AAA Session with Id {}", sessionId);
Hardik Windlass75c67712020-02-21 10:57:20 +00001191
Girish Kumar064084c2020-02-04 08:32:46 +00001192 flushStateMachineSession(sessionId,
Matteo Scandoloe033c262020-10-14 11:37:39 -07001193 StateMachine.SessionTerminationReasons.PORT_REMOVED.getReason());
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +00001194
Girish Kumar064084c2020-02-04 08:32:46 +00001195 break;
Girish Kumar064084c2020-02-04 08:32:46 +00001196 case DEVICE_REMOVED:
Girish Kumar064084c2020-02-04 08:32:46 +00001197 log.debug("Received DEVICE_REMOVED event for {}", deviceId);
Andrea Campanellabba33672020-02-11 14:03:01 +01001198 clearAllSessionStateForDevice(deviceId);
Amit Ghoshf739be52017-09-21 15:49:37 +01001199 break;
Girish Kumar064084c2020-02-04 08:32:46 +00001200
Amit Ghoshf739be52017-09-21 15:49:37 +01001201 default:
1202 return;
1203 }
1204 }
Girish Kumar064084c2020-02-04 08:32:46 +00001205
Andrea Campanellabba33672020-02-11 14:03:01 +01001206 private void clearAllSessionStateForDevice(DeviceId deviceId) {
1207 Set<String> associatedSessions = Sets.newHashSet();
1208 for (Entry<String, StateMachine> stateMachineEntry : stateMachines.entrySet()) {
1209 ConnectPoint cp = stateMachineEntry.getValue().supplicantConnectpoint();
1210 if (cp != null && cp.deviceId().toString().equals(deviceId.toString())) {
1211 associatedSessions.add(stateMachineEntry.getKey());
1212 }
1213 }
1214
1215 for (String session : associatedSessions) {
1216 log.debug("Clearing AAA Session {} associated with Removed Device", session);
1217 flushStateMachineSession(session,
Matteo Scandoloe033c262020-10-14 11:37:39 -07001218 StateMachine.SessionTerminationReasons.DEVICE_REMOVED.getReason());
Andrea Campanellabba33672020-02-11 14:03:01 +01001219 }
1220 }
1221
Girish Kumar064084c2020-02-04 08:32:46 +00001222 private void flushStateMachineSession(String sessionId, String terminationReason) {
1223 StateMachine stateMachine = stateMachines.get(sessionId);
Girish Kumare5a1aa92020-02-14 14:08:54 +00001224 if (stateMachine == null) {
1225 // No active AAA sessions for this UNI port
1226 log.debug("No Active AAA Session found with Id {}", sessionId);
1227 return;
Girish Kumar064084c2020-02-04 08:32:46 +00001228 }
1229
Hardik Windlass9a09b832020-02-25 11:45:35 +00001230 authentications.remove(stateMachine.supplicantConnectpoint());
Girish Kumare5a1aa92020-02-14 14:08:54 +00001231 stateMachine.setSessionTerminateReason(terminationReason);
1232
Girish Kumar064084c2020-02-04 08:32:46 +00001233 //pushing captured machine stats to kafka
1234 AaaSupplicantMachineStats obj = aaaSupplicantStatsManager.getSupplicantStats(stateMachine);
1235 aaaSupplicantStatsManager.getMachineStatsDelegate()
Matteo Scandoloe033c262020-10-14 11:37:39 -07001236 .notify(new AaaMachineStatisticsEvent(AaaMachineStatisticsEvent.Type.STATS_UPDATE, obj));
Girish Kumar064084c2020-02-04 08:32:46 +00001237 StateMachine removed = stateMachines.remove(sessionId);
Shubham Sharma8d7a9822020-01-28 10:04:01 +00001238
Girish Kumar064084c2020-02-04 08:32:46 +00001239 if (removed != null) {
1240 StateMachine.deleteStateMachineMapping(removed);
1241 }
1242 }
Amit Ghoshf739be52017-09-21 15:49:37 +01001243 }
Girish Kumar064084c2020-02-04 08:32:46 +00001244
Shubham Sharma4900ce62019-06-19 14:18:50 +00001245 private class ServerStatusChecker implements Runnable {
1246 @Override
1247 public void run() {
Matteo Scandolo3498bc02020-01-08 09:54:12 -08001248 log.debug("Notifying RadiusOperationalStatusEvent");
Shubham Sharma4900ce62019-06-19 14:18:50 +00001249 radiusOperationalStatusService.checkServerOperationalStatus();
Matteo Scandolo3498bc02020-01-08 09:54:12 -08001250 log.trace("--POSTING--" + radiusOperationalStatusService.getRadiusServerOperationalStatus());
Shubham Sharma4900ce62019-06-19 14:18:50 +00001251 radiusOperationalStatusService.getRadiusOprStDelegate()
Matteo Scandoloe033c262020-10-14 11:37:39 -07001252 .notify(new RadiusOperationalStatusEvent(
1253 RadiusOperationalStatusEvent.Type.RADIUS_OPERATIONAL_STATUS,
1254 radiusOperationalStatusService.
1255 getRadiusServerOperationalStatus()));
kartikey dubeye1545422019-05-22 12:53:45 +00001256 }
Shubham Sharma4900ce62019-06-19 14:18:50 +00001257
1258 }
Shubham Sharma544ffa22020-02-13 06:41:02 +00001259
1260 @Override
1261 public AaaSupplicantMachineStats getSupplicantMachineStats(String sessionId) {
1262 StateMachine aaaSupplicantMachine = stateMachines.get(sessionId);
1263 if (aaaSupplicantMachine != null) {
1264 return aaaSupplicantStatsManager.getSupplicantStats(aaaSupplicantMachine);
1265 } else {
1266 return null;
1267 }
1268 }
Jonathan Hart612651f2019-11-25 09:21:43 -08001269}