blob: d95075364089ea35d8f4706e7af0ea8b6212c635 [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;
Matteo Scandolo9510e5d2020-09-24 17:31:52 -070019
Andrea Campanellac4781e62020-10-08 12:58:45 +020020import static java.util.concurrent.Executors.newSingleThreadExecutor;
Matteo Scandolo9510e5d2020-09-24 17:31:52 -070021import static org.onlab.util.Tools.groupedThreads;
Girish Kumar064084c2020-02-04 08:32:46 +000022import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
Matteo Scandolo9510e5d2020-09-24 17:31:52 -070023import static org.opencord.aaa.impl.OsgiPropertyConstants.*;
Girish Kumar064084c2020-02-04 08:32:46 +000024import static org.slf4j.LoggerFactory.getLogger;
25
Ilayda Ozdemir9fdeee72021-02-26 12:24:27 +000026import com.google.common.collect.Maps;
Girish Kumar064084c2020-02-04 08:32:46 +000027import 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;
Ilayda Ozdemir9fdeee72021-02-26 12:24:27 +0000104import org.osgi.service.component.annotations.ReferencePolicy;
Ari Saha89831742015-06-26 10:31:48 -0700105import org.slf4j.Logger;
106
Shubham Sharma4900ce62019-06-19 14:18:50 +0000107import javax.crypto.Mac;
108import javax.crypto.spec.SecretKeySpec;
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800109import java.util.Optional;
Jonathan Hart612651f2019-11-25 09:21:43 -0800110import java.util.concurrent.ConcurrentMap;
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700111import java.util.concurrent.ExecutorService;
kartikey dubeye1545422019-05-22 12:53:45 +0000112import java.util.concurrent.Executors;
113import java.util.concurrent.ScheduledExecutorService;
114import java.util.concurrent.ScheduledFuture;
115import java.util.concurrent.TimeUnit;
Vijaykumar Kushwaha056e4cd2019-08-06 13:16:25 +0000116
Ari Saha89831742015-06-26 10:31:48 -0700117/**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700118 * AAA application for ONOS.
Ari Saha89831742015-06-26 10:31:48 -0700119 */
Carmelo Cascone58b53292019-09-30 12:35:31 -0700120@Component(immediate = true, property = {
Shubham Sharma4900ce62019-06-19 14:18:50 +0000121 OPERATIONAL_STATUS_SERVER_EVENT_GENERATION + ":Integer=" + OPERATIONAL_STATUS_SERVER_EVENT_GENERATION_DEFAULT,
122 OPERATIONAL_STATUS_SERVER_TIMEOUT + ":Integer=" + OPERATIONAL_STATUS_SERVER_TIMEOUT_DEFAULT,
123 STATUS_SERVER_MODE + ":String=" + STATUS_SERVER_MODE_DEFAULT,
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700124 PACKET_PROCESSOR_THREADS + ":Integer=" + PACKET_PROCESSOR_THREADS_DEFAULT,
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -0700125 FORGE_EAPOL_PACKETS + ":Boolean=" + FORGE_EAPOL_PACKETS_DEFAULT,
Carmelo Cascone58b53292019-09-30 12:35:31 -0700126})
Jonathan Hart5db44532018-07-12 18:13:54 -0700127public class AaaManager
128 extends AbstractListenerManager<AuthenticationEvent, AuthenticationEventListener>
129 implements AuthenticationService {
Ilayda Ozdemir9fdeee72021-02-26 12:24:27 +0000130 private static final String SADIS_NOT_RUNNING = "Sadis is not running.";
Charles Chandf7ff862017-01-20 11:22:05 -0800131 private static final String APP_NAME = "org.opencord.aaa";
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700132 private static final int STATE_MACHINE_THREADS = 3;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700133
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700134 private final Logger log = getLogger(getClass());
Ray Milkeyf51eba22015-09-25 10:24:23 -0700135
Carmelo Cascone58b53292019-09-30 12:35:31 -0700136 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700137 protected CoreService coreService;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700138
Carmelo Cascone58b53292019-09-30 12:35:31 -0700139 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800140 protected StorageService storageService;
141
142 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700143 protected PacketService packetService;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700144
Carmelo Cascone58b53292019-09-30 12:35:31 -0700145 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700146 protected NetworkConfigRegistry netCfgService;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700147
Carmelo Cascone58b53292019-09-30 12:35:31 -0700148 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100149 protected DeviceService deviceService;
150
Ilayda Ozdemir9fdeee72021-02-26 12:24:27 +0000151 @Reference(cardinality = ReferenceCardinality.OPTIONAL,
152 bind = "bindSadisService",
153 unbind = "unbindSadisService",
154 policy = ReferencePolicy.DYNAMIC)
155 protected volatile SadisService sadisService;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100156
Carmelo Cascone58b53292019-09-30 12:35:31 -0700157 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100158 protected MastershipService mastershipService;
159
Carmelo Cascone58b53292019-09-30 12:35:31 -0700160 @Reference(cardinality = ReferenceCardinality.MANDATORY)
kartikey dubeye1545422019-05-22 12:53:45 +0000161 protected AuthenticationStatisticsService aaaStatisticsManager;
Gamze Abaka1cfdb192018-10-25 11:39:19 +0000162
Carmelo Cascone58b53292019-09-30 12:35:31 -0700163 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +0000164 protected AaaMachineStatisticsService aaaSupplicantStatsManager;
165
166 @Reference(cardinality = ReferenceCardinality.MANDATORY)
kartikey dubeye1545422019-05-22 12:53:45 +0000167 protected ComponentConfigService cfgService;
168
Shubham Sharma4900ce62019-06-19 14:18:50 +0000169 @Reference(cardinality = ReferenceCardinality.MANDATORY)
170 protected RadiusOperationalStatusService radiusOperationalStatusService;
171
kartikey dubeye1545422019-05-22 12:53:45 +0000172 protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
Amit Ghoshf739be52017-09-21 15:49:37 +0100173 private final DeviceListener deviceListener = new InternalDeviceListener();
174
Shubham Sharma4900ce62019-06-19 14:18:50 +0000175 // Properties
Shubham Sharma4900ce62019-06-19 14:18:50 +0000176 private int operationalStatusEventGenerationPeriodInSeconds = OPERATIONAL_STATUS_SERVER_EVENT_GENERATION_DEFAULT;
177 private int operationalStatusServerTimeoutInSeconds = OPERATIONAL_STATUS_SERVER_TIMEOUT_DEFAULT;
178 protected String operationalStatusEvaluationMode = STATUS_SERVER_MODE_DEFAULT;
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -0700179
180 /**
181 * If set to true the RADIUS server won't be involved in authentication.
182 **/
183 private Boolean forgeEapolPackets = FORGE_EAPOL_PACKETS_DEFAULT;
184
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700185 /**
186 * Number of threads used to process the packet.
187 */
188 protected int packetProcessorThreads = PACKET_PROCESSOR_THREADS_DEFAULT;
kartikey dubeye1545422019-05-22 12:53:45 +0000189
Jonathan Hart612651f2019-11-25 09:21:43 -0800190 private IdentifierManager idManager;
191
192 private ConcurrentMap<String, StateMachine> stateMachines;
193
Hardik Windlassd0b49692020-02-26 18:17:14 +0000194 private ConsistentMap<ConnectPoint, AuthenticationRecord> authenticationsConsistentMap;
Matteo Scandolo120d40b2020-11-25 15:49:22 -0800195 // NOTE consider to change this map to be Map<DeviceId,Map<ConnectPoint, AuthenticationRecord>> so that
196 // we can iterate on smalled collection when dealing with authentications
Hardik Windlassd0b49692020-02-26 18:17:14 +0000197 private Map<ConnectPoint, AuthenticationRecord> authentications;
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800198
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700199 // NAS IP address
200 protected InetAddress nasIpAddress;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100201
202 // self MAC address
Jonathan Hart5db44532018-07-12 18:13:54 -0700203 protected String nasMacAddress;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100204
205 // Parsed RADIUS server addresses
206 protected InetAddress radiusIpAddress;
207
208 // MAC address of RADIUS server or net hop router
209 protected String radiusMacAddress;
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700210
211 // RADIUS server secret
212 protected String radiusSecret;
213
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100214 // bindings
215 protected CustomizationInfo customInfo;
Ray Milkey5d99bd12015-10-06 15:41:30 -0700216
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700217 // our application-specific event handler
218 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
Ray Milkeyf51eba22015-09-25 10:24:23 -0700219
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700220 // our unique identifier
221 private ApplicationId appId;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700222
Shubham Sharma1e43c562019-06-19 14:18:12 +0000223 // TimeOut time for cleaning up stateMachines stuck due to pending AAA/EAPOL message.
224 protected int cleanupTimerTimeOutInMins;
225
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100226 // Setup specific customization/attributes on the RADIUS packets
227 PacketCustomizer pktCustomizer;
Ray Milkey967776a2015-10-07 14:37:17 -0700228
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100229 // packet customizer to use
230 private String customizer;
231
232 // Type of connection to use to communicate with Radius server, options are
233 // "socket" or "packet_out"
234 private String radiusConnectionType;
235
Jonathan Hart5db44532018-07-12 18:13:54 -0700236 // Object for the specific type of communication with the RADIUS
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100237 // server, socket based or packet_out based
238 RadiusCommunicator impl = null;
239
240 // latest configuration
241 AaaConfig newCfg;
Ray Milkey967776a2015-10-07 14:37:17 -0700242
Shubham Sharma4900ce62019-06-19 14:18:50 +0000243 ScheduledFuture<?> scheduledStatusServerChecker;
kartikey dubeye1545422019-05-22 12:53:45 +0000244 String configuredAaaServerAddress;
Jonathan Hartc41227c2020-01-28 16:56:49 -0800245 HashSet<Byte> outPacketSet = new HashSet<>();
246 HashSet<Byte> outPacketSupp = new HashSet<>();
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000247 static final List<Byte> VALID_EAPOL_TYPE = Arrays.asList(EAPOL.EAPOL_START, EAPOL.EAPOL_LOGOFF, EAPOL.EAPOL_PACKET);
248 static final int HEADER_LENGTH = 4;
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700249 // Configuration properties factory
250 private final ConfigFactory factory =
Jonathan Hart092dfb22015-11-16 23:05:21 -0800251 new ConfigFactory<ApplicationId, AaaConfig>(APP_SUBJECT_FACTORY,
Ilayda Ozdemir9fdeee72021-02-26 12:24:27 +0000252 AaaConfig.class,
253 "AAA") {
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700254 @Override
Jonathan Hart092dfb22015-11-16 23:05:21 -0800255 public AaaConfig createConfig() {
256 return new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700257 }
258 };
Ray Milkeyf51eba22015-09-25 10:24:23 -0700259
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700260 // Listener for config changes
261 private final InternalConfigListener cfgListener = new InternalConfigListener();
Ari Saha89831742015-06-26 10:31:48 -0700262
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800263 private final InternalMapEventListener mapListener = new InternalMapEventListener();
264
Jonathan Hart5db44532018-07-12 18:13:54 -0700265 private StateMachineDelegate delegate = new InternalStateMachineDelegate();
266
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700267 protected ExecutorService packetProcessorExecutor;
268 protected ScheduledExecutorService serverStatusAndStateMachineTimeoutExecutor;
Matteo Scandoloe033c262020-10-14 11:37:39 -0700269
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700270 /**
271 * Builds an EAPOL packet based on the given parameters.
272 *
273 * @param dstMac destination MAC address
274 * @param srcMac source MAC address
275 * @param vlan vlan identifier
276 * @param eapolType EAPOL type
277 * @param eap EAP payload
278 * @return Ethernet frame
279 */
280 private static Ethernet buildEapolResponse(MacAddress dstMac, MacAddress srcMac,
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100281 short vlan, byte eapolType, EAP eap, byte priorityCode) {
Ari Saha89831742015-06-26 10:31:48 -0700282
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700283 Ethernet eth = new Ethernet();
284 eth.setDestinationMACAddress(dstMac.toBytes());
285 eth.setSourceMACAddress(srcMac.toBytes());
286 eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
287 if (vlan != Ethernet.VLAN_UNTAGGED) {
288 eth.setVlanID(vlan);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100289 eth.setPriorityCode(priorityCode);
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700290 }
291 //eapol header
292 EAPOL eapol = new EAPOL();
293 eapol.setEapolType(eapolType);
294 eapol.setPacketLength(eap.getLength());
Ari Saha89831742015-06-26 10:31:48 -0700295
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700296 //eap part
297 eapol.setPayload(eap);
298
299 eth.setPayload(eapol);
300 eth.setPad(true);
301 return eth;
302 }
Ari Saha89831742015-06-26 10:31:48 -0700303
Ari Saha89831742015-06-26 10:31:48 -0700304 @Activate
kartikey dubeye1545422019-05-22 12:53:45 +0000305 public void activate(ComponentContext context) {
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700306
Jonathan Hart612651f2019-11-25 09:21:43 -0800307 idManager = new IdentifierManager();
308 stateMachines = Maps.newConcurrentMap();
Charles Chandf7ff862017-01-20 11:22:05 -0800309 appId = coreService.registerApplication(APP_NAME);
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800310
311 KryoNamespace authSerializer = KryoNamespace.newBuilder()
Jonathan Hartc41227c2020-01-28 16:56:49 -0800312 .register(KryoNamespaces.API)
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800313 .register(AuthenticationRecord.class)
314 .build();
315
Hardik Windlassd0b49692020-02-26 18:17:14 +0000316 authenticationsConsistentMap = storageService.<ConnectPoint, AuthenticationRecord>consistentMapBuilder()
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800317 .withApplicationId(appId)
318 .withName("authentications")
319 .withSerializer(Serializer.using(authSerializer))
320 .build();
Hardik Windlassd0b49692020-02-26 18:17:14 +0000321 authenticationsConsistentMap.addListener(mapListener);
322 authentications = authenticationsConsistentMap.asJavaMap();
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800323
Jonathan Hart5db44532018-07-12 18:13:54 -0700324 eventDispatcher.addSink(AuthenticationEvent.class, listenerRegistry);
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400325 netCfgService.addListener(cfgListener);
326 netCfgService.registerConfigFactory(factory);
kartikey dubeye1545422019-05-22 12:53:45 +0000327 cfgService.registerProperties(getClass());
328 modified(context);
Ilayda Ozdemir9fdeee72021-02-26 12:24:27 +0000329 if (sadisService != null) {
330 subsService = sadisService.getSubscriberInfoService();
331 } else {
332 log.warn(SADIS_NOT_RUNNING);
333 }
334 if (customInfo == null) {
335 customInfo = new CustomizationInfo(subsService, deviceService);
336 }
Jonathan Hart092dfb22015-11-16 23:05:21 -0800337 cfgListener.reconfigureNetwork(netCfgService.getConfig(appId, AaaConfig.class));
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400338 log.info("Starting with config {} {}", this, newCfg);
Ilayda Ozdemir9fdeee72021-02-26 12:24:27 +0000339 configureRadiusCommunication(false);
Ari Saha89831742015-06-26 10:31:48 -0700340 // register our event handler
Brian O'Connord9c7da02015-07-29 17:49:24 -0700341 packetService.addProcessor(processor, PacketProcessor.director(2));
Jonathan Hart5db44532018-07-12 18:13:54 -0700342 StateMachine.setDelegate(delegate);
Shubham Sharma1e43c562019-06-19 14:18:12 +0000343 cleanupTimerTimeOutInMins = newCfg.sessionCleanupTimer();
344 StateMachine.setcleanupTimerTimeOutInMins(cleanupTimerTimeOutInMins);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100345 impl.initializeLocalState(newCfg);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100346 impl.requestIntercepts();
Amit Ghoshf739be52017-09-21 15:49:37 +0100347 deviceService.addListener(deviceListener);
kartikey dubeye1545422019-05-22 12:53:45 +0000348 getConfiguredAaaServerAddress();
Shubham Sharma4900ce62019-06-19 14:18:50 +0000349 radiusOperationalStatusService.initialize(nasIpAddress.getAddress(), radiusSecret, impl);
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700350 serverStatusAndStateMachineTimeoutExecutor = Executors.newScheduledThreadPool(STATE_MACHINE_THREADS,
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -0700351 groupedThreads("onos/aaa", "machine-%d", log));
Shubham Sharma4900ce62019-06-19 14:18:50 +0000352
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700353 scheduledStatusServerChecker = serverStatusAndStateMachineTimeoutExecutor.scheduleAtFixedRate(
354 new ServerStatusChecker(), 0,
355 operationalStatusEventGenerationPeriodInSeconds, TimeUnit.SECONDS);
Jian Li13c67162015-12-09 13:20:34 -0800356 log.info("Started");
Ari Saha89831742015-06-26 10:31:48 -0700357 }
358
359 @Deactivate
kartikey dubeye1545422019-05-22 12:53:45 +0000360 public void deactivate(ComponentContext context) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100361 impl.withdrawIntercepts();
Ari Saha89831742015-06-26 10:31:48 -0700362 packetService.removeProcessor(processor);
Deepa Vaddireddyb9c24c62017-09-21 13:45:30 +0530363 netCfgService.removeListener(cfgListener);
kartikey dubeye1545422019-05-22 12:53:45 +0000364 cfgService.unregisterProperties(getClass(), false);
Jonathan Hart5db44532018-07-12 18:13:54 -0700365 StateMachine.unsetDelegate(delegate);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100366 impl.deactivate();
Ilayda Ozdemir9fdeee72021-02-26 12:24:27 +0000367 impl = null;
Amit Ghoshf739be52017-09-21 15:49:37 +0100368 deviceService.removeListener(deviceListener);
Jonathan Hart5db44532018-07-12 18:13:54 -0700369 eventDispatcher.removeSink(AuthenticationEvent.class);
Shubham Sharma4900ce62019-06-19 14:18:50 +0000370 scheduledStatusServerChecker.cancel(true);
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700371 serverStatusAndStateMachineTimeoutExecutor.shutdown();
372 packetProcessorExecutor.shutdown();
Hardik Windlassd0b49692020-02-26 18:17:14 +0000373 authenticationsConsistentMap.removeListener(mapListener);
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800374
Jian Li13c67162015-12-09 13:20:34 -0800375 log.info("Stopped");
Ray Milkey967776a2015-10-07 14:37:17 -0700376 }
Matteo Scandoloe033c262020-10-14 11:37:39 -0700377
kartikey dubeye1545422019-05-22 12:53:45 +0000378 @Modified
379 public void modified(ComponentContext context) {
Shubham Sharma4900ce62019-06-19 14:18:50 +0000380 Dictionary<String, Object> properties = context.getProperties();
381
Jonathan Hartc41227c2020-01-28 16:56:49 -0800382 String s = Tools.get(properties, "operationalStatusEventGenerationPeriodInSeconds");
Shubham Sharma4900ce62019-06-19 14:18:50 +0000383 operationalStatusEventGenerationPeriodInSeconds = Strings.isNullOrEmpty(s)
384 ? OPERATIONAL_STATUS_SERVER_EVENT_GENERATION_DEFAULT
Matteo Scandoloe033c262020-10-14 11:37:39 -0700385 : Integer.parseInt(s.trim());
Shubham Sharma4900ce62019-06-19 14:18:50 +0000386
387 s = Tools.get(properties, "operationalStatusServerTimeoutInSeconds");
388 operationalStatusServerTimeoutInSeconds = Strings.isNullOrEmpty(s) ? OPERATIONAL_STATUS_SERVER_TIMEOUT_DEFAULT
389 : Integer.parseInt(s.trim());
390
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -0700391 Boolean p = Tools.isPropertyEnabled(properties, FORGE_EAPOL_PACKETS);
392 forgeEapolPackets = (p == null) ? FORGE_EAPOL_PACKETS_DEFAULT : p;
393
Shubham Sharma4900ce62019-06-19 14:18:50 +0000394 s = Tools.get(properties, "operationalStatusEvaluationMode");
395 String newEvaluationModeString = Strings.isNullOrEmpty(s) ? STATUS_SERVER_MODE_DEFAULT : s.trim();
396
397 radiusOperationalStatusService
Matteo Scandoloe033c262020-10-14 11:37:39 -0700398 .setOperationalStatusServerTimeoutInMillis(operationalStatusServerTimeoutInSeconds * 1000);
Shubham Sharma4900ce62019-06-19 14:18:50 +0000399 RadiusOperationalStatusEvaluationMode newEvaluationMode =
400 RadiusOperationalStatusEvaluationMode.getValue(newEvaluationModeString);
401 if (newEvaluationMode != null) {
402 radiusOperationalStatusService.setRadiusOperationalStatusEvaluationMode(newEvaluationMode);
403 operationalStatusEvaluationMode = newEvaluationModeString;
404 } else {
405 properties.put("operationalStatusEvaluationMode", operationalStatusEvaluationMode);
406 }
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700407
408 s = Tools.get(properties, PACKET_PROCESSOR_THREADS);
409 int oldpacketProcessorThreads = packetProcessorThreads;
410 packetProcessorThreads = Strings.isNullOrEmpty(s) ? oldpacketProcessorThreads
411 : Integer.parseInt(s.trim());
412 if (packetProcessorExecutor == null || oldpacketProcessorThreads != packetProcessorThreads) {
413 if (packetProcessorExecutor != null) {
414 packetProcessorExecutor.shutdown();
415 }
Matteo Scandoloe033c262020-10-14 11:37:39 -0700416 packetProcessorExecutor = newSingleThreadExecutor(
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -0700417 groupedThreads("onos/aaa", "packet-%d", log));
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700418 }
kartikey dubeye1545422019-05-22 12:53:45 +0000419 }
420
Ilayda Ozdemir9fdeee72021-02-26 12:24:27 +0000421 protected void bindSadisService(SadisService service) {
422 sadisService = service;
423 subsService = sadisService.getSubscriberInfoService();
424 if (customInfo == null) {
425 customInfo = new CustomizationInfo(subsService, deviceService);
426 } else {
427 customInfo.updateSubscriberService(subsService);
428 }
429 if (radiusConnectionType == null) {
430 log.debug("Configuration is not init yet.");
431 } else {
432 refreshRadiusCommunication();
433 }
434 log.info("Sadis-service binds to onos.");
435 }
436
437 protected void unbindSadisService(SadisService service) {
438 sadisService = null;
439 subsService = null;
440 customInfo.updateSubscriberService(subsService);
441 refreshRadiusCommunication();
442 log.info("Sadis-service unbinds from onos.");
443 }
444
445 private void refreshRadiusCommunication() {
446 if (!radiusConnectionType.toLowerCase().equals("socket")) {
447 if (impl != null) {
448 impl.withdrawIntercepts();
449 impl.clearLocalState();
450 }
451 configureRadiusCommunication(true);
452 impl.initializeLocalState(newCfg);
453 impl.requestIntercepts();
454 }
455 }
456
457 protected void configureRadiusCommunication(boolean isUpdate) {
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530458 if (radiusConnectionType.toLowerCase().equals("socket")) {
459 impl = new SocketBasedRadiusCommunicator(appId, packetService, this);
460 } else {
Ilayda Ozdemir9fdeee72021-02-26 12:24:27 +0000461 if (impl != null && isUpdate) {
462 //update subsService
463 ((PortBasedRadiusCommunicator) impl).updateSubsService(subsService);
464 } else {
465 impl = new PortBasedRadiusCommunicator(appId, packetService, mastershipService,
466 deviceService, subsService, pktCustomizer, this);
467 }
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530468 }
469 }
470
471 private void configurePacketCustomizer() {
472 switch (customizer.toLowerCase()) {
473 case "sample":
474 pktCustomizer = new SamplePacketCustomizer(customInfo);
475 log.info("Created SamplePacketCustomizer");
476 break;
Saurav Dase72358a2018-11-13 21:56:46 -0800477 case "att":
478 pktCustomizer = new AttPacketCustomizer(customInfo);
479 log.info("Created AttPacketCustomizer");
480 break;
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530481 default:
482 pktCustomizer = new PacketCustomizer(customInfo);
483 log.info("Created default PacketCustomizer");
484 break;
485 }
486 }
487
kartikey dubeye1545422019-05-22 12:53:45 +0000488 private void getConfiguredAaaServerAddress() {
489 try {
490 InetAddress address;
491 if (newCfg.radiusHostName() != null) {
492 address = InetAddress.getByName(newCfg.radiusHostName());
493 } else {
Matteo Scandoloe033c262020-10-14 11:37:39 -0700494 address = newCfg.radiusIp();
kartikey dubeye1545422019-05-22 12:53:45 +0000495 }
496
497 configuredAaaServerAddress = address.getHostAddress();
498 } catch (UnknownHostException uhe) {
499 log.warn("Unable to resolve host {}", newCfg.radiusHostName());
500 }
501 }
502
Vijaykumar Kushwaha056e4cd2019-08-06 13:16:25 +0000503 private void checkReceivedPacketForValidValidator(RADIUS radiusPacket, byte[] requestAuthenticator) {
504 if (!checkResponseMessageAuthenticator(radiusSecret, radiusPacket, requestAuthenticator)) {
kartikey dubeye1545422019-05-22 12:53:45 +0000505 aaaStatisticsManager.getAaaStats().increaseInvalidValidatorsRx();
506 }
507 }
Vijaykumar Kushwaha056e4cd2019-08-06 13:16:25 +0000508
509 private boolean checkResponseMessageAuthenticator(String key, RADIUS radiusPacket, byte[] requestAuthenticator) {
510 byte[] newHash = new byte[16];
511 Arrays.fill(newHash, (byte) 0);
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -0700512 // looking for the attributes - exit if there are no such attributes
513 if (radiusPacket.getAttributeList(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH).isEmpty()) {
514 log.warn("Empty Attribute List for packet {} with identifier {}",
515 radiusPacket, radiusPacket.getIdentifier());
516 return false;
517 }
518 // get the attribute - further verify if it is null or not (not really needed)
519 RADIUSAttribute attribute = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH);
520 if (attribute == null) {
521 log.warn("Null Message Authenticator for packet {} with identifier {}",
522 radiusPacket, radiusPacket.getIdentifier());
523 return false;
524 }
525 byte[] messageAuthenticator = attribute.getValue();
Vijaykumar Kushwaha056e4cd2019-08-06 13:16:25 +0000526 byte[] authenticator = radiusPacket.getAuthenticator();
527 radiusPacket.updateAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH, newHash);
528 radiusPacket.setAuthenticator(requestAuthenticator);
529 // Calculate the MD5 HMAC based on the message
530 try {
531 SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "HmacMD5");
532 Mac mac = Mac.getInstance("HmacMD5");
533 mac.init(keySpec);
534 newHash = mac.doFinal(radiusPacket.serialize());
535 } catch (Exception e) {
536 log.error("Failed to generate message authenticator: {}", e.getMessage());
537 }
538 radiusPacket.updateAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH, messageAuthenticator);
539 radiusPacket.setAuthenticator(authenticator);
540 // Compare the calculated Message-Authenticator with the one in the message
541 return Arrays.equals(newHash, messageAuthenticator);
542 }
Matteo Scandoloe033c262020-10-14 11:37:39 -0700543
kartikey dubeye1545422019-05-22 12:53:45 +0000544 public void checkForPacketFromUnknownServer(String hostAddress) {
Matteo Scandoloe033c262020-10-14 11:37:39 -0700545 if (!hostAddress.equals(configuredAaaServerAddress)) {
546 getConfiguredAaaServerAddress();
kartikey dubeye1545422019-05-22 12:53:45 +0000547 if (!hostAddress.equals(configuredAaaServerAddress)) {
Matteo Scandoloe033c262020-10-14 11:37:39 -0700548 aaaStatisticsManager.getAaaStats().incrementUnknownServerRx();
kartikey dubeye1545422019-05-22 12:53:45 +0000549 }
Matteo Scandoloe033c262020-10-14 11:37:39 -0700550 }
kartikey dubeye1545422019-05-22 12:53:45 +0000551 }
552
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100553 /**
554 * Send RADIUS packet to the RADIUS server.
555 *
556 * @param radiusPacket RADIUS packet to be sent to server.
557 * @param inPkt Incoming EAPOL packet
558 */
559 protected void sendRadiusPacket(RADIUS radiusPacket, InboundPacket inPkt) {
kartikey dubeye1545422019-05-22 12:53:45 +0000560 outPacketSet.add(radiusPacket.getIdentifier());
561 aaaStatisticsManager.getAaaStats().increaseOrDecreasePendingRequests(true);
562 aaaStatisticsManager.getAaaStats().increaseAccessRequestsTx();
Shubham Sharma4900ce62019-06-19 14:18:50 +0000563 aaaStatisticsManager.putOutgoingIdentifierToMap(radiusPacket.getIdentifier());
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100564 impl.sendRadiusPacket(radiusPacket, inPkt);
565 }
Ray Milkey967776a2015-10-07 14:37:17 -0700566
Jonathan Hart612651f2019-11-25 09:21:43 -0800567 /**
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100568 * Handles RADIUS packets.
569 *
570 * @param radiusPacket RADIUS packet coming from the RADIUS server.
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100571 */
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700572 public void handleRadiusPacket(RADIUS radiusPacket) {
Andrea Campanellac4781e62020-10-08 12:58:45 +0200573 if (log.isTraceEnabled()) {
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -0700574 log.trace("Received RADIUS packet {} with identifier {}",
575 radiusPacket, radiusPacket.getIdentifier() & 0xff);
Andrea Campanellac4781e62020-10-08 12:58:45 +0200576 }
577 if (radiusOperationalStatusService.isRadiusResponseForOperationalStatus(radiusPacket.getIdentifier())) {
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -0700578 if (log.isTraceEnabled()) {
579 log.trace("Handling operational status RADIUS packet {} with identifier {}",
580 radiusPacket, radiusPacket.getIdentifier() & 0xff);
581 }
Andrea Campanellac4781e62020-10-08 12:58:45 +0200582 radiusOperationalStatusService.handleRadiusPacketForOperationalStatus(radiusPacket);
583 return;
584 }
Jonathan Hart612651f2019-11-25 09:21:43 -0800585
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -0700586 if (log.isTraceEnabled()) {
587 log.trace("Handling actual RADIUS packet for supplicant {} with identifier {}",
588 radiusPacket, radiusPacket.getIdentifier() & 0xff);
589 }
590
Andrea Campanellac4781e62020-10-08 12:58:45 +0200591 RequestIdentifier identifier = RequestIdentifier.of(radiusPacket.getIdentifier());
592 String sessionId = idManager.getSessionId(identifier);
Jonathan Hart612651f2019-11-25 09:21:43 -0800593
Andrea Campanellac4781e62020-10-08 12:58:45 +0200594 if (sessionId == null) {
595 log.error("Invalid packet identifier {}, could not find corresponding "
596 + "state machine ... exiting", radiusPacket.getIdentifier());
597 aaaStatisticsManager.getAaaStats().incrementNumberOfSessionsExpired();
598 aaaStatisticsManager.getAaaStats().countDroppedResponsesRx();
599 return;
600 }
Jonathan Hart612651f2019-11-25 09:21:43 -0800601
Andrea Campanellac4781e62020-10-08 12:58:45 +0200602 idManager.releaseIdentifier(identifier);
603 StateMachine stateMachine = stateMachines.get(sessionId);
604 if (stateMachine == null) {
605 log.error("Invalid packet identifier {}, could not find corresponding "
606 + "state machine ... exiting", radiusPacket.getIdentifier());
607 aaaStatisticsManager.getAaaStats().incrementNumberOfSessionsExpired();
608 aaaStatisticsManager.getAaaStats().countDroppedResponsesRx();
609 return;
610 }
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +0000611
Andrea Campanellac4781e62020-10-08 12:58:45 +0200612 //instance of StateMachine using the sessionId for updating machine stats
613 StateMachine machineStats = stateMachines.get(stateMachine.sessionId());
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +0000614
Andrea Campanellac4781e62020-10-08 12:58:45 +0200615 EAP eapPayload;
616 Ethernet eth;
617 checkReceivedPacketForValidValidator(radiusPacket, stateMachine.requestAuthenticator());
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +0000618
Andrea Campanellac4781e62020-10-08 12:58:45 +0200619 //increasing packets and octets received from server
620 machineStats.incrementTotalPacketsReceived();
621 try {
622 machineStats.incrementTotalOctetReceived(radiusPacket.decapsulateMessage().getLength());
623 } catch (DeserializationException e) {
624 log.error(e.getMessage());
625 return;
626 }
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700627
Andrea Campanellac4781e62020-10-08 12:58:45 +0200628 if (outPacketSet.contains(radiusPacket.getIdentifier())) {
629 aaaStatisticsManager.getAaaStats().increaseOrDecreasePendingRequests(false);
630 outPacketSet.remove(new Byte(radiusPacket.getIdentifier()));
631 }
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700632
Andrea Campanellac4781e62020-10-08 12:58:45 +0200633 MacAddress dstMac = stateMachine.supplicantAddress();
634 ConnectPoint supplicantCp = stateMachine.supplicantConnectpoint();
635 switch (radiusPacket.getCode()) {
636 case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE:
Matteo Scandoloe033c262020-10-14 11:37:39 -0700637 log.debug("RADIUS packet: RADIUS_CODE_ACCESS_CHALLENGE for dev/port: {}/{} " +
638 "with MacAddress {} and Identifier {}",
639 supplicantCp.deviceId(), supplicantCp.port(), dstMac, radiusPacket.getIdentifier() & 0xff);
Andrea Campanellac4781e62020-10-08 12:58:45 +0200640 RADIUSAttribute radiusAttrState = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE);
641 byte[] challengeState = null;
642 if (radiusAttrState != null) {
643 challengeState = radiusAttrState.getValue();
644 }
645 try {
646 eapPayload = radiusPacket.decapsulateMessage();
647 eth = buildEapolResponse(stateMachine.supplicantAddress(),
648 MacAddress.valueOf(nasMacAddress),
649 stateMachine.vlanId(),
650 EAPOL.EAPOL_PACKET,
651 eapPayload, stateMachine.priorityCode());
652 stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState);
653 } catch (DeserializationException e) {
654 log.error(e.getMessage());
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700655 break;
Andrea Campanellac4781e62020-10-08 12:58:45 +0200656 }
Matteo Scandoloe033c262020-10-14 11:37:39 -0700657 log.debug("Send EAP challenge response to supplicant on dev/port: {}/{}" +
658 " with MacAddress {} and Identifier {}",
659 supplicantCp.deviceId(), supplicantCp.port(), dstMac, radiusPacket.getIdentifier() & 0xff);
Andrea Campanellac4781e62020-10-08 12:58:45 +0200660 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint(), true);
661 aaaStatisticsManager.getAaaStats().increaseChallengeResponsesRx();
662 outPacketSupp.add(eapPayload.getIdentifier());
Andrea Campanella76ae68d2020-10-14 11:16:37 +0200663 aaaStatisticsManager.getAaaStats().incrementPendingReqSupp();
Andrea Campanellac4781e62020-10-08 12:58:45 +0200664 //increasing packets send to server
665 machineStats.incrementTotalPacketsSent();
666 machineStats.incrementTotalOctetSent(eapPayload.getLength());
667 break;
668 case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
Matteo Scandoloe033c262020-10-14 11:37:39 -0700669 log.debug("RADIUS packet: RADIUS_CODE_ACCESS_ACCEPT for dev/port: {}/{}" +
670 " with MacAddress {} and Identifier {}",
671 supplicantCp.deviceId(), supplicantCp.port(), dstMac, radiusPacket.getIdentifier() & 0xff);
Andrea Campanellac4781e62020-10-08 12:58:45 +0200672 //send an EAPOL - Success to the supplicant.
673 byte[] eapMessageSuccess =
674 radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
675 try {
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700676 eapPayload = EAP.deserializer().deserialize(
677 eapMessageSuccess, 0, eapMessageSuccess.length);
Andrea Campanellac4781e62020-10-08 12:58:45 +0200678 } catch (DeserializationException e) {
679 log.error(e.getMessage());
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700680 break;
Andrea Campanellac4781e62020-10-08 12:58:45 +0200681 }
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700682
Andrea Campanellac4781e62020-10-08 12:58:45 +0200683 eth = buildEapolResponse(stateMachine.supplicantAddress(),
684 MacAddress.valueOf(nasMacAddress),
685 stateMachine.vlanId(),
686 EAPOL.EAPOL_PACKET,
687 eapPayload, stateMachine.priorityCode());
Matteo Scandoloe033c262020-10-14 11:37:39 -0700688 log.info("Send EAP success message to supplicant on dev/port: {}/{}" +
689 " with MacAddress {} and Identifier {}",
690 supplicantCp.deviceId(), supplicantCp.port(), dstMac, radiusPacket.getIdentifier() & 0xff);
Andrea Campanellac4781e62020-10-08 12:58:45 +0200691 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint(), false);
692 aaaStatisticsManager.getAaaStats().incrementEapolAuthSuccessTrans();
693
694 stateMachine.authorizeAccess();
695 aaaStatisticsManager.getAaaStats().increaseAcceptResponsesRx();
696 //increasing packets send to server
697 machineStats.incrementTotalPacketsSent();
698 machineStats.incrementTotalOctetSent(eapPayload.getLength());
699 break;
700 case RADIUS.RADIUS_CODE_ACCESS_REJECT:
Matteo Scandoloe033c262020-10-14 11:37:39 -0700701 log.debug("RADIUS packet: RADIUS_CODE_ACCESS_REJECT for dev/port: {}/{}" +
702 " with MacAddress {} and Identifier {}",
703 supplicantCp.deviceId(), supplicantCp.port(), dstMac, radiusPacket.getIdentifier() & 0xff);
Andrea Campanellac4781e62020-10-08 12:58:45 +0200704 //send an EAPOL - Failure to the supplicant.
705 byte[] eapMessageFailure;
706 eapPayload = new EAP();
707 RADIUSAttribute radiusAttrEap = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE);
708 if (radiusAttrEap == null) {
709 eapPayload.setCode(EAP.FAILURE);
710 eapPayload.setIdentifier(stateMachine.challengeIdentifier());
711 eapPayload.setLength(EAP.EAP_HDR_LEN_SUC_FAIL);
712 } else {
713 eapMessageFailure = radiusAttrEap.getValue();
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700714 try {
Andrea Campanellac4781e62020-10-08 12:58:45 +0200715 eapPayload = EAP.deserializer().deserialize(
716 eapMessageFailure, 0, eapMessageFailure.length);
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700717 } catch (DeserializationException e) {
718 log.error(e.getMessage());
719 break;
720 }
Andrea Campanellac4781e62020-10-08 12:58:45 +0200721 }
722 eth = buildEapolResponse(stateMachine.supplicantAddress(),
723 MacAddress.valueOf(nasMacAddress),
724 stateMachine.vlanId(),
725 EAPOL.EAPOL_PACKET,
726 eapPayload, stateMachine.priorityCode());
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -0700727 log.warn("Send EAP failure message to supplicant on dev/port: {}/{}" +
Matteo Scandoloe033c262020-10-14 11:37:39 -0700728 " with MacAddress {} and Identifier {}", supplicantCp.deviceId(), supplicantCp.port(),
729 dstMac, stateMachine.challengeIdentifier() & 0xff);
Andrea Campanellac4781e62020-10-08 12:58:45 +0200730 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint(), false);
731 aaaStatisticsManager.getAaaStats().incrementEapolauthFailureTrans();
732
733 stateMachine.denyAccess();
734 aaaStatisticsManager.getAaaStats().increaseRejectResponsesRx();
735 //increasing packets send to server
736 machineStats.incrementTotalPacketsSent();
737 machineStats.incrementTotalOctetSent(eapPayload.getLength());
738 //pushing machine stats to kafka
739 AaaSupplicantMachineStats machineObj = aaaSupplicantStatsManager.getSupplicantStats(machineStats);
740 aaaSupplicantStatsManager.getMachineStatsDelegate()
741 .notify(new AaaMachineStatisticsEvent(AaaMachineStatisticsEvent.Type.STATS_UPDATE,
742 machineObj));
743 break;
744 default:
Matteo Scandoloe033c262020-10-14 11:37:39 -0700745 log.warn("Unknown RADIUS message received with code: {} for dev/port: {}/{}" +
746 " with MacAddress {} and Identifier {}",
747 radiusPacket.getCode(), supplicantCp.deviceId(), supplicantCp.port(), dstMac,
748 radiusPacket.getIdentifier() & 0xff);
Andrea Campanellac4781e62020-10-08 12:58:45 +0200749 aaaStatisticsManager.getAaaStats().increaseUnknownTypeRx();
750 //increasing packets received to server
751 machineStats.incrementTotalPacketsReceived();
752 try {
753 machineStats.incrementTotalOctetReceived(radiusPacket.decapsulateMessage().getLength());
754 } catch (DeserializationException e) {
755 log.error(e.getMessage());
756 break;
757 }
758 }
759 aaaStatisticsManager.getAaaStats().countDroppedResponsesRx();
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700760 }
761
Ray Milkey967776a2015-10-07 14:37:17 -0700762 /**
763 * Send the ethernet packet to the supplicant.
764 *
765 * @param ethernetPkt the ethernet packet
766 * @param connectPoint the connect point to send out
767 */
Shubham Sharma1f193582019-07-11 12:12:41 +0000768 private void sendPacketToSupplicant(Ethernet ethernetPkt, ConnectPoint connectPoint, boolean isChallengeResponse) {
Ray Milkey967776a2015-10-07 14:37:17 -0700769 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
770 OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(),
771 treatment, ByteBuffer.wrap(ethernetPkt.serialize()));
Shubham Sharma1f193582019-07-11 12:12:41 +0000772 EAPOL eap = ((EAPOL) ethernetPkt.getPayload());
Saurav Das987441a2018-09-18 16:33:47 -0700773 if (log.isTraceEnabled()) {
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -0700774 log.trace("Sending eapol payload {} to supplicant at {} with MacAddress {}",
775 eap, connectPoint, ethernetPkt.getDestinationMAC());
Saurav Das987441a2018-09-18 16:33:47 -0700776 }
Ray Milkey967776a2015-10-07 14:37:17 -0700777 packetService.emit(packet);
Shubham Sharma1f193582019-07-11 12:12:41 +0000778 if (isChallengeResponse) {
779 aaaStatisticsManager.getAaaStats().incrementEapPktTxauthEap();
780 }
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000781 aaaStatisticsManager.getAaaStats().incrementEapolFramesTx();
782 aaaStatisticsManager.getAaaStats().countReqEapFramesTx();
Ray Milkey967776a2015-10-07 14:37:17 -0700783 }
784
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400785 @Override
786 public String toString() {
787 return ToStringBuilder.reflectionToString(this);
788 }
789
Jonathan Hart612651f2019-11-25 09:21:43 -0800790 @Override
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800791 public Iterable<AuthenticationRecord> getAuthenticationRecords() {
Hardik Windlassd0b49692020-02-26 18:17:14 +0000792 return authentications.values();
Jonathan Hart612651f2019-11-25 09:21:43 -0800793 }
794
795 @Override
796 public boolean removeAuthenticationStateByMac(MacAddress mac) {
797
Hardik Windlassd0b49692020-02-26 18:17:14 +0000798 Optional<AuthenticationRecord> r = authentications.values().stream()
799 .filter(v -> v.supplicantAddress().equals(mac))
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800800 .findFirst();
Jonathan Hart612651f2019-11-25 09:21:43 -0800801
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800802 if (r.isEmpty()) {
803 return false;
Jonathan Hart612651f2019-11-25 09:21:43 -0800804 }
805
Hardik Windlassd0b49692020-02-26 18:17:14 +0000806 AuthenticationRecord removed =
807 authentications.remove(r.get().supplicantConnectPoint());
Jonathan Hart612651f2019-11-25 09:21:43 -0800808
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800809 return removed != null;
Jonathan Hart612651f2019-11-25 09:21:43 -0800810 }
811
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800812 StateMachine getStateMachine(String sessionId) {
Jonathan Hart612651f2019-11-25 09:21:43 -0800813 return stateMachines.get(sessionId);
814 }
815
Ari Saha89831742015-06-26 10:31:48 -0700816 // our handler defined as a private inner class
817
818 /**
819 * Packet processor responsible for forwarding packets along their paths.
820 */
821 private class ReactivePacketProcessor implements PacketProcessor {
822 @Override
823 public void process(PacketContext context) {
Andrea Campanellac4781e62020-10-08 12:58:45 +0200824 packetProcessorExecutor.execute(() -> {
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -0700825 try {
826 // Extract the original Ethernet frame from the packet information
827 InboundPacket pkt = context.inPacket();
828 if (pkt == null) {
829 log.warn("Dropping inbound packet as it can't be parsed (inpacket)");
830 return;
831 }
832 Ethernet ethPkt = pkt.parsed();
833 if (ethPkt == null) {
834 log.warn("Dropping inbound packet as it can't be parsed (ethpacket)");
835 return;
836 }
Ari Saha89831742015-06-26 10:31:48 -0700837
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -0700838 EthType.EtherType pktType;
839 try {
840 short ethType = ethPkt.getEtherType();
841 pktType = EthType.EtherType.lookup(ethType);
842 } catch (Exception e) {
843 log.error("Exception while reading packet type", e);
844 return;
845 }
846
847 // identify if incoming packet comes from supplicant (EAP) or RADIUS
848 switch (pktType) {
849 case EAPOL:
850 if (log.isTraceEnabled()) {
851 log.trace("Received EAPOL supplicant packet from dev/port: {} with MacAddress {}",
852 context.inPacket().receivedFrom(), ethPkt.getSourceMAC());
853 }
854 handleSupplicantPacket(context.inPacket());
855 break;
856 default:
857 // any other packets let the specific implementation handle
858 if (log.isTraceEnabled()) {
859 log.trace("Received packet-in from RADIUS server {} in enclosing packet {} from "
860 + "dev/port: {} with MacAddress {}", ethPkt, context.inPacket(),
861 context.inPacket().receivedFrom(), ethPkt.getSourceMAC());
862 }
863 impl.handlePacketFromServer(context);
864 }
865 } catch (Exception e) {
866 log.error("Error while processing packet", e);
Andrea Campanellac4781e62020-10-08 12:58:45 +0200867 }
868 });
Ari Saha89831742015-06-26 10:31:48 -0700869 }
870
Ray Milkey9eb293f2015-09-30 15:09:17 -0700871 /**
872 * Creates and initializes common fields of a RADIUS packet.
873 *
Ray Milkey967776a2015-10-07 14:37:17 -0700874 * @param stateMachine state machine for the request
Matteo Scandoloe033c262020-10-14 11:37:39 -0700875 * @param eapPacket EAP packet
Ray Milkey9eb293f2015-09-30 15:09:17 -0700876 * @return RADIUS packet
877 */
Ray Milkey967776a2015-10-07 14:37:17 -0700878 private RADIUS getRadiusPayload(StateMachine stateMachine, byte identifier, EAP eapPacket) {
Ray Milkey9eb293f2015-09-30 15:09:17 -0700879 RADIUS radiusPayload =
880 new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
881 eapPacket.getIdentifier());
Ray Milkey967776a2015-10-07 14:37:17 -0700882
883 // set Request Authenticator in StateMachine
884 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
885
Ray Milkey9eb293f2015-09-30 15:09:17 -0700886 radiusPayload.setIdentifier(identifier);
887 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
Ray Milkey967776a2015-10-07 14:37:17 -0700888 stateMachine.username());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700889
890 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
Matteo Scandoloe033c262020-10-14 11:37:39 -0700891 AaaManager.this.nasIpAddress.getAddress());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700892
893 radiusPayload.encapsulateMessage(eapPacket);
Ray Milkey9eb293f2015-09-30 15:09:17 -0700894
895 return radiusPayload;
896 }
Ari Saha89831742015-06-26 10:31:48 -0700897
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -0700898 private void handleEapolStart(InboundPacket inPacket, StateMachine stateMachine) {
899
900 DeviceId deviceId = inPacket.receivedFrom().deviceId();
901 PortNumber portNumber = inPacket.receivedFrom().port();
902 Ethernet ethPkt = inPacket.parsed();
903 MacAddress srcMac = ethPkt.getSourceMAC();
904
905 log.debug("EAP packet: EAPOL_START from dev/port: {}/{} with MacAddress {}",
906 deviceId, portNumber, srcMac);
907 stateMachine.setSupplicantConnectpoint(inPacket.receivedFrom());
908 stateMachine.setSupplicantAddress(srcMac);
909 stateMachine.start();
910
911 aaaStatisticsManager.getAaaStats().incrementEapolStartReqRx();
912 //send an EAP Request/Identify to the supplicant
913 EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.identifier(), EAP.ATTR_IDENTITY, null);
914 if (ethPkt.getVlanID() != Ethernet.VLAN_UNTAGGED) {
915 stateMachine.setPriorityCode(ethPkt.getPriorityCode());
916 }
917 Ethernet eth = buildEapolResponse(srcMac, MacAddress.valueOf(nasMacAddress),
918 ethPkt.getVlanID(), EAPOL.EAPOL_PACKET,
919 eapPayload, stateMachine.priorityCode());
920
921 stateMachine.setVlanId(ethPkt.getVlanID());
922 log.debug("Getting EAP identity from supplicant {}", stateMachine.supplicantAddress().toString());
923 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint(), false);
924 aaaStatisticsManager.getAaaStats().incrementRequestIdFramesTx();
925 }
926
927 private void hangleEapolLogoff(InboundPacket inPacket, StateMachine stateMachine) {
928
929 DeviceId deviceId = inPacket.receivedFrom().deviceId();
930 PortNumber portNumber = inPacket.receivedFrom().port();
931 Ethernet ethPkt = inPacket.parsed();
932 MacAddress srcMac = ethPkt.getSourceMAC();
933
934 log.debug("EAP packet: EAPOL_LOGOFF from dev/port: {}/{} with MacAddress {}",
935 deviceId, portNumber, srcMac);
936 //posting the machine stat data for current supplicant device.
937 if (stateMachine.getSessionTerminateReason() == null ||
938 stateMachine.getSessionTerminateReason().equals("")) {
939 stateMachine.setSessionTerminateReason(
940 StateMachine.SessionTerminationReasons.SUPPLICANT_LOGOFF.getReason());
941 }
942 AaaSupplicantMachineStats obj = aaaSupplicantStatsManager.getSupplicantStats(stateMachine);
943 aaaSupplicantStatsManager.getMachineStatsDelegate()
944 .notify(new AaaMachineStatisticsEvent(AaaMachineStatisticsEvent.Type.STATS_UPDATE, obj));
945 if (stateMachine.state() == StateMachine.STATE_AUTHORIZED) {
946 stateMachine.logoff();
947 aaaStatisticsManager.getAaaStats().incrementEapolLogoffRx();
948 }
949 if (stateMachine.state() == StateMachine.STATE_IDLE) {
950 aaaStatisticsManager.getAaaStats().incrementAuthStateIdle();
951 }
952 }
953
954 private void handleForgedEapolChallengeAuth(StateMachine stateMachine) {
955 stateMachine.requestAccess();
956
957 log.info("Forging EAP auth challenge");
958 byte[] challengeState = EapolPacketGenerator.hexStringToByteArray("19056d66190469d738db2f7dc1e02591");
959 EAP eapPayload = EapolPacketGenerator.forgeEapolChallengeAuth();
960
961 Ethernet eth = buildEapolResponse(stateMachine.supplicantAddress(),
962 MacAddress.valueOf(nasMacAddress),
963 stateMachine.vlanId(),
964 EAPOL.EAPOL_PACKET,
965 eapPayload, stateMachine.priorityCode());
966 stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState);
967
968 ConnectPoint supplicantCp = stateMachine.supplicantConnectpoint();
969 MacAddress dstMac = stateMachine.supplicantAddress();
970 log.info("Send FORGED EAP auth challenge to supplicant {} on dev/port: {}/{} with MacAddress {}",
971 supplicantCp.deviceId(), supplicantCp.port(), dstMac);
972
973 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint(),
974 true);
975
976 // NOTE do we care about stats?
977 }
978
979 private void handleForgedEapolSuccess(StateMachine stateMachine) {
980 ConnectPoint supplicantCp = stateMachine.supplicantConnectpoint();
981 MacAddress dstMac = stateMachine.supplicantAddress();
982 log.info("Forging EAP auth success");
983 EAP eapPayload = EapolPacketGenerator.forgeEapolSuccess();
984
985 Ethernet eth = buildEapolResponse(stateMachine.supplicantAddress(),
986 MacAddress.valueOf(nasMacAddress),
987 stateMachine.vlanId(),
988 EAPOL.EAPOL_PACKET,
989 eapPayload, stateMachine.priorityCode());
990 log.info("Send FORGED EAP success message to supplicant {} on dev/port: {}/{} with MacAddress {}",
991 supplicantCp.deviceId(), supplicantCp.port(), dstMac);
992 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint(), false);
993 aaaStatisticsManager.getAaaStats().incrementEapolAuthSuccessTrans();
994
995 stateMachine.authorizeAccess();
996 }
997
998
Ari Saha89831742015-06-26 10:31:48 -0700999 /**
Jonathan Harta46dddf2015-06-30 15:31:20 -07001000 * Handles PAE packets (supplicant).
1001 *
1002 * @param inPacket Ethernet packet coming from the supplicant
Ari Saha89831742015-06-26 10:31:48 -07001003 */
Jonathan Hart612651f2019-11-25 09:21:43 -08001004 private void handleSupplicantPacket(InboundPacket inPacket) {
Matteo Scandoloe033c262020-10-14 11:37:39 -07001005
Jonathan Harta46dddf2015-06-30 15:31:20 -07001006 Ethernet ethPkt = inPacket.parsed();
Ari Saha89831742015-06-26 10:31:48 -07001007 // Where does it come from?
Jonathan Hart092dfb22015-11-16 23:05:21 -08001008 MacAddress srcMac = ethPkt.getSourceMAC();
Ari Saha89831742015-06-26 10:31:48 -07001009
Jonathan Harta46dddf2015-06-30 15:31:20 -07001010 DeviceId deviceId = inPacket.receivedFrom().deviceId();
1011 PortNumber portNumber = inPacket.receivedFrom().port();
Andrea Campanellad8023322021-03-22 17:40:39 +01001012 String sessionId = inPacket.receivedFrom().toString();
Saurav Das987441a2018-09-18 16:33:47 -07001013 EAPOL eapol = (EAPOL) ethPkt.getPayload();
Matteo Scandoloe033c262020-10-14 11:37:39 -07001014
Saurav Das987441a2018-09-18 16:33:47 -07001015 if (log.isTraceEnabled()) {
1016 log.trace("Received EAPOL packet {} in enclosing packet {} from "
Matteo Scandoloe033c262020-10-14 11:37:39 -07001017 + "dev/port: {}/{} with MacAddress {} and type {}",
1018 eapol, ethPkt, deviceId, portNumber, srcMac, eapol.getEapolType());
Amit Ghoshc9ac1e52017-07-28 12:31:18 +01001019 }
Jonathan Harta46dddf2015-06-30 15:31:20 -07001020
Shubham Sharma3c8c7022019-09-13 10:39:47 +00001021 short pktlen = eapol.getPacketLength();
1022 byte[] eapPayLoadBuffer = eapol.serialize();
1023 int len = eapPayLoadBuffer.length;
1024 if (len != (HEADER_LENGTH + pktlen)) {
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -07001025 log.warn("Invalid EAPOL pkt length {} (shoudl be {}) for packet {} from dev/port: {}/{} " +
1026 "with MacAddress {}, dropping it",
1027 len, HEADER_LENGTH + pktlen, eapol, deviceId, portNumber, srcMac);
Shubham Sharma3c8c7022019-09-13 10:39:47 +00001028 aaaStatisticsManager.getAaaStats().incrementInvalidBodyLength();
1029 return;
1030 }
1031 if (!VALID_EAPOL_TYPE.contains(eapol.getEapolType())) {
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -07001032 log.warn("Invalid EAPOL Type {} for packet {} from dev/port: {}/{} with MacAddress {}, dropping it",
Matteo Scandoloe033c262020-10-14 11:37:39 -07001033 eapol.getEapolType(), eapol, deviceId, portNumber, srcMac);
Shubham Sharma3c8c7022019-09-13 10:39:47 +00001034 aaaStatisticsManager.getAaaStats().incrementInvalidPktType();
1035 return;
1036 }
1037 if (pktlen >= 0 && ethPkt.getEtherType() == EthType.EtherType.EAPOL.ethType().toShort()) {
1038 aaaStatisticsManager.getAaaStats().incrementValidEapolFramesRx();
1039 }
Matteo Scandolo9510e5d2020-09-24 17:31:52 -07001040 StateMachine stateMachine = stateMachines.computeIfAbsent(sessionId, id ->
1041 new StateMachine(id, serverStatusAndStateMachineTimeoutExecutor));
Jonathan Hart612651f2019-11-25 09:21:43 -08001042 stateMachine.setEapolTypeVal(eapol.getEapolType());
Saurav Das987441a2018-09-18 16:33:47 -07001043
Ari Saha89831742015-06-26 10:31:48 -07001044 switch (eapol.getEapolType()) {
1045 case EAPOL.EAPOL_START:
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -07001046 handleEapolStart(inPacket, stateMachine);
Ari Saha89831742015-06-26 10:31:48 -07001047 break;
Qianqian Hub55a1ac2015-12-23 20:44:48 +08001048 case EAPOL.EAPOL_LOGOFF:
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -07001049 hangleEapolLogoff(inPacket, stateMachine);
Qianqian Hub55a1ac2015-12-23 20:44:48 +08001050 break;
Ari Saha89831742015-06-26 10:31:48 -07001051 case EAPOL.EAPOL_PACKET:
Matteo Scandoloe033c262020-10-14 11:37:39 -07001052
Ray Milkey9eb293f2015-09-30 15:09:17 -07001053 // check if this is a Response/Identify or a Response/TLS
Ari Saha89831742015-06-26 10:31:48 -07001054 EAP eapPacket = (EAP) eapol.getPayload();
Shubham Sharma3c8c7022019-09-13 10:39:47 +00001055 Byte identifier = new Byte(eapPacket.getIdentifier());
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -07001056
Matteo Scandoloe033c262020-10-14 11:37:39 -07001057 log.debug("EAP packet: EAPOL_PACKET from dev/port: {}/{} with MacAddress {} with Identifier {}",
1058 deviceId, portNumber, srcMac, identifier.doubleValue());
Jonathan Hart612651f2019-11-25 09:21:43 -08001059
Ari Saha89831742015-06-26 10:31:48 -07001060 byte dataType = eapPacket.getDataType();
Matteo Scandoloe033c262020-10-14 11:37:39 -07001061
Ari Saha89831742015-06-26 10:31:48 -07001062 switch (dataType) {
Ray Milkey9eb293f2015-09-30 15:09:17 -07001063 case EAP.ATTR_IDENTITY:
Matteo Scandoloe033c262020-10-14 11:37:39 -07001064 handleAttrIdentity(inPacket, srcMac, deviceId, portNumber,
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -07001065 eapol, stateMachine, eapPacket, sessionId);
Ray Milkey9eb293f2015-09-30 15:09:17 -07001066 break;
Ari Saha89831742015-06-26 10:31:48 -07001067 case EAP.ATTR_MD5:
Matteo Scandoloe033c262020-10-14 11:37:39 -07001068 handleMD5(inPacket, srcMac, deviceId, portNumber, stateMachine,
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -07001069 eapPacket, identifier, sessionId);
Ari Saha89831742015-06-26 10:31:48 -07001070 break;
1071 case EAP.ATTR_TLS:
Matteo Scandoloe033c262020-10-14 11:37:39 -07001072 handleTls(inPacket, srcMac, deviceId, portNumber, stateMachine,
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -07001073 eapPacket, identifier, sessionId);
Ari Saha89831742015-06-26 10:31:48 -07001074 break;
1075 default:
Matteo Scandoloe033c262020-10-14 11:37:39 -07001076 log.warn("Unknown EAP packet type from dev/port: {}/{} with MacAddress {} and " +
1077 "Identifier {}", deviceId, portNumber, srcMac, eapPacket.getIdentifier() & 0xff);
Ari Saha89831742015-06-26 10:31:48 -07001078 return;
1079 }
1080 break;
1081 default:
Andrea Campanellac4781e62020-10-08 12:58:45 +02001082 log.debug("Skipping EAPOL message {} from dev/port: {}/{} with MacAddress {}",
1083 eapol.getEapolType(), deviceId, portNumber, srcMac);
Ari Saha89831742015-06-26 10:31:48 -07001084 }
Shubham Sharma1f193582019-07-11 12:12:41 +00001085 aaaStatisticsManager.getAaaStats().countTransRespNotNak();
1086 aaaStatisticsManager.getAaaStats().countEapolResIdentityMsgTrans();
Ari Saha89831742015-06-26 10:31:48 -07001087 }
Matteo Scandoloe033c262020-10-14 11:37:39 -07001088
1089 private void handleAttrIdentity(InboundPacket inPacket, MacAddress srcMac, DeviceId deviceId,
1090 PortNumber portNumber, EAPOL eapol, StateMachine stateMachine,
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -07001091 EAP eapPacket, String sessionId) {
Matteo Scandoloe033c262020-10-14 11:37:39 -07001092
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -07001093 if (forgeEapolPackets) {
1094 handleForgedEapolChallengeAuth(stateMachine);
1095 return;
1096 } else {
1097 // get identifier for request and store mapping to session ID
1098 RequestIdentifier radiusIdentifier = idManager.getNewIdentifier(sessionId);
1099 if (radiusIdentifier == null) {
1100 log.warn("Cannot get identifier supplicant at dev/port: {}/{} " +
1101 "with MacAddress {}, dropping packet",
1102 deviceId, portNumber, srcMac);
1103 return;
1104 }
1105 log.debug("EAP packet: EAPOL_PACKET ATTR_IDENTITY from dev/port: {}/{} with MacAddress {}" +
1106 " and Identifier {}", deviceId, portNumber, srcMac, eapPacket.getIdentifier() & 0xff);
1107 //Setting the time of this response from RG, only when its not a re-transmission.
1108 if (stateMachine.getLastPacketReceivedTime() == 0) {
1109 stateMachine.setLastPacketReceivedTime(System.currentTimeMillis());
1110 }
1111 // request id access to RADIUS
1112 stateMachine.setUsername(eapPacket.getData());
Matteo Scandoloe033c262020-10-14 11:37:39 -07001113
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -07001114 RADIUS radiusPayload = getRadiusPayload(stateMachine, radiusIdentifier.identifier(), eapPacket);
1115 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
1116 radiusPayload.addMessageAuthenticator(radiusSecret);
Matteo Scandoloe033c262020-10-14 11:37:39 -07001117
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -07001118 if (log.isTraceEnabled()) {
1119 log.trace("Sending ATTR_IDENTITY packet to RADIUS for supplicant at dev/port: " +
1120 "{}/{} with MacAddress {} and Identifier {}", deviceId, portNumber,
Matteo Scandolo105210b2020-12-10 10:32:39 -08001121 srcMac, radiusIdentifier.getReadableIdentifier());
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -07001122 }
1123
1124 sendRadiusPacket(radiusPayload, inPacket);
1125 stateMachine.setWaitingForRadiusResponse(true);
1126 aaaStatisticsManager.getAaaStats().incrementRadiusReqIdTx();
1127 aaaStatisticsManager.getAaaStats().incrementEapolAtrrIdentity();
1128 // change the state to "PENDING"
1129 if (stateMachine.state() == StateMachine.STATE_PENDING) {
1130 aaaStatisticsManager.getAaaStats().increaseRequestReTx();
1131 stateMachine.incrementTotalPacketsSent();
1132 stateMachine.incrementTotalOctetSent(eapol.getPacketLength());
1133 }
1134 stateMachine.requestAccess();
Matteo Scandoloe033c262020-10-14 11:37:39 -07001135 }
Matteo Scandoloe033c262020-10-14 11:37:39 -07001136 }
1137
1138 private void handleMD5(InboundPacket inPacket, MacAddress srcMac, DeviceId deviceId,
1139 PortNumber portNumber, StateMachine stateMachine, EAP eapPacket,
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -07001140 Byte identifier, String sessionId) {
1141 // get identifier for request and store mapping to session ID
1142 RequestIdentifier radiusIdentifier = idManager.getNewIdentifier(sessionId);
1143 if (radiusIdentifier == null) {
1144 log.warn("Cannot get identifier supplicant at dev/port: {}/{} " +
1145 "with MacAddress {}, dropping packet",
1146 deviceId, portNumber, srcMac);
1147 return;
1148 }
1149
Matteo Scandoloe033c262020-10-14 11:37:39 -07001150 log.debug("EAP packet: EAPOL_PACKET ATTR_MD5 from dev/port: {}/{} with MacAddress {}" +
1151 " and Identifier {}", deviceId, portNumber, srcMac, eapPacket.getIdentifier() & 0xff);
1152 // verify if the EAP identifier corresponds to the
1153 // challenge identifier from the client state
1154 // machine.
1155 stateMachine.setLastPacketReceivedTime(System.currentTimeMillis());
1156 if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) {
1157 //send the RADIUS challenge response
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -07001158 if (forgeEapolPackets) {
1159 handleForgedEapolSuccess(stateMachine);
1160 } else {
1161 RADIUS radiusPayload = getRadiusPayload(stateMachine,
1162 radiusIdentifier.identifier(), eapPacket);
1163 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Matteo Scandoloe033c262020-10-14 11:37:39 -07001164
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -07001165 if (stateMachine.challengeState() != null) {
1166 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
1167 stateMachine.challengeState());
1168 }
1169 radiusPayload.addMessageAuthenticator(radiusSecret);
1170 if (outPacketSupp.contains(eapPacket.getIdentifier())) {
1171 aaaStatisticsManager.getAaaStats().decrementPendingReqSupp();
1172 outPacketSupp.remove(identifier);
1173 }
1174 if (log.isTraceEnabled()) {
1175 log.trace("Sending ATTR_MD5 packet to RADIUS for supplicant at dev/port: {}/{}" +
1176 " with MacAddress {} and Identifier {}", deviceId, portNumber, srcMac,
Matteo Scandolo105210b2020-12-10 10:32:39 -08001177 radiusIdentifier.getReadableIdentifier());
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -07001178 }
1179 sendRadiusPacket(radiusPayload, inPacket);
1180 stateMachine.setWaitingForRadiusResponse(true);
1181 aaaStatisticsManager.getAaaStats().incrementRadiusReqChallengeTx();
1182 aaaStatisticsManager.getAaaStats().incrementEapolMd5RspChall();
Matteo Scandoloe033c262020-10-14 11:37:39 -07001183 }
Matteo Scandoloe033c262020-10-14 11:37:39 -07001184 } else {
1185 log.error("eapolIdentifier {} and stateMachine Identifier {} do not " +
1186 "correspond for packet from dev/port: {}/{} with MacAddress {}",
1187 eapPacket.getIdentifier() & 0xff, stateMachine.challengeIdentifier() & 0xff,
1188 deviceId, portNumber, srcMac);
1189 aaaStatisticsManager.getAaaStats().incrementEapolMd5RspChall();
1190 if (outPacketSupp.contains(eapPacket.getIdentifier())) {
1191 aaaStatisticsManager.getAaaStats().decrementPendingReqSupp();
1192 outPacketSupp.remove(identifier);
1193 }
1194 aaaStatisticsManager.getAaaStats().incrementEapolauthFailureTrans();
1195 }
1196 }
1197
1198
1199 private void handleTls(InboundPacket inPacket, MacAddress srcMac, DeviceId deviceId,
1200 PortNumber portNumber, StateMachine stateMachine, EAP eapPacket,
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -07001201 Byte identifier, String sessionId) {
1202 // get identifier for request and store mapping to session ID
1203 RequestIdentifier radiusIdentifier = idManager.getNewIdentifier(sessionId);
1204
1205 if (radiusIdentifier == null) {
1206 log.warn("Cannot get identifier supplicant at dev/port: {}/{} " +
1207 "with MacAddress {}, dropping packet", deviceId, portNumber, srcMac);
1208 return;
1209 }
Matteo Scandoloe033c262020-10-14 11:37:39 -07001210 log.debug("EAP packet: EAPOL_PACKET ATTR_TLS from dev/port: {}/{} with MacAddress {} " +
1211 "and Identifier {}", deviceId, portNumber, srcMac, eapPacket.getIdentifier() & 0xff);
1212 // request id access to RADIUS
Matteo Scandolobbc1ffb2020-10-16 15:56:20 -07001213 RADIUS radiusPayload = getRadiusPayload(stateMachine, radiusIdentifier.identifier(), eapPacket);
Matteo Scandoloe033c262020-10-14 11:37:39 -07001214 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
1215 if (stateMachine.challengeState() != null) {
1216 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
1217 stateMachine.challengeState());
1218 }
1219 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
1220 radiusPayload.addMessageAuthenticator(radiusSecret);
1221 if (outPacketSupp.contains(eapPacket.getIdentifier())) {
1222 aaaStatisticsManager.getAaaStats().decrementPendingReqSupp();
1223 outPacketSupp.remove(identifier);
1224 }
1225 if (log.isTraceEnabled()) {
1226 log.trace("Sending ATTR_TLS packet to RADIUS for supplicant at dev/port: {}/{} with " +
1227 "MacAddress {} and Identifier {}", deviceId, portNumber, srcMac,
Matteo Scandolo105210b2020-12-10 10:32:39 -08001228 radiusIdentifier.getReadableIdentifier());
Matteo Scandoloe033c262020-10-14 11:37:39 -07001229 }
1230 sendRadiusPacket(radiusPayload, inPacket);
1231 stateMachine.setWaitingForRadiusResponse(true);
1232 aaaStatisticsManager.getAaaStats().incrementRadiusReqChallengeTx();
1233 aaaStatisticsManager.getAaaStats().incrementEapolTlsRespChall();
1234 if (stateMachine.state() != StateMachine.STATE_PENDING) {
1235 stateMachine.requestAccess();
1236 }
1237 }
Ray Milkey967776a2015-10-07 14:37:17 -07001238 }
1239
Amit Ghoshc9ac1e52017-07-28 12:31:18 +01001240 /**
Jonathan Hart5db44532018-07-12 18:13:54 -07001241 * Delegate allowing the StateMachine to notify us of events.
1242 */
1243 private class InternalStateMachineDelegate implements StateMachineDelegate {
1244
1245 @Override
1246 public void notify(AuthenticationEvent authenticationEvent) {
1247 log.info("Auth event {} for {}",
Matteo Scandoloe033c262020-10-14 11:37:39 -07001248 authenticationEvent.type(), authenticationEvent.subject());
Jonathan Hart612651f2019-11-25 09:21:43 -08001249
1250 if (authenticationEvent.type() == AuthenticationEvent.Type.TIMEOUT) {
1251 handleStateMachineTimeout(authenticationEvent.subject());
1252 }
1253
Jonathan Hart9d1ce802020-01-28 10:45:08 -08001254 AuthenticationRecord record = authenticationEvent.authenticationRecord();
1255 if (record == null) {
1256 authentications.remove(authenticationEvent.subject());
1257 } else {
1258 authentications.put(authenticationEvent.subject(), record);
1259 }
1260
Jonathan Hart5db44532018-07-12 18:13:54 -07001261 post(authenticationEvent);
1262 }
1263 }
1264
Jonathan Hart612651f2019-11-25 09:21:43 -08001265 private void handleStateMachineTimeout(ConnectPoint supplicantConnectPoint) {
Andrea Campanellad8023322021-03-22 17:40:39 +01001266 StateMachine stateMachine = stateMachines.remove(supplicantConnectPoint.toString());
Andrea Campanellae66466a2020-02-03 14:05:45 +00001267 //pushing captured machine stats to kafka
1268 stateMachine.setSessionTerminateReason("Time out");
1269 AaaSupplicantMachineStats obj = aaaSupplicantStatsManager
1270 .getSupplicantStats(stateMachine);
1271 aaaSupplicantStatsManager.getMachineStatsDelegate()
1272 .notify(new AaaMachineStatisticsEvent(
1273 AaaMachineStatisticsEvent.Type.STATS_UPDATE, obj));
1274
Jonathan Hart612651f2019-11-25 09:21:43 -08001275 if (stateMachine.state() == StateMachine.STATE_PENDING && stateMachine.isWaitingForRadiusResponse()) {
1276 aaaStatisticsManager.getAaaStats().increaseTimedOutPackets();
1277 }
1278
1279 StateMachine.deleteStateMachineMapping(stateMachine);
1280 }
1281
Jonathan Hart5db44532018-07-12 18:13:54 -07001282 /**
Amit Ghoshc9ac1e52017-07-28 12:31:18 +01001283 * Configuration Listener, handles change in configuration.
1284 */
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001285 private class InternalConfigListener implements NetworkConfigListener {
1286
1287 /**
Ray Milkeyc9e8dcc2015-12-30 10:31:32 -08001288 * Reconfigures the AAA application according to the
1289 * configuration parameters passed.
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001290 *
1291 * @param cfg configuration object
1292 */
Jonathan Hart092dfb22015-11-16 23:05:21 -08001293 private void reconfigureNetwork(AaaConfig cfg) {
Matt Jeanneret2ff1a782018-06-13 15:24:25 -04001294 log.info("Reconfiguring AaaConfig from config: {}", cfg);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +01001295
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001296 if (cfg == null) {
Jonathan Hart092dfb22015-11-16 23:05:21 -08001297 newCfg = new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001298 } else {
1299 newCfg = cfg;
1300 }
1301 if (newCfg.nasIp() != null) {
1302 nasIpAddress = newCfg.nasIp();
1303 }
1304 if (newCfg.radiusIp() != null) {
1305 radiusIpAddress = newCfg.radiusIp();
1306 }
1307 if (newCfg.radiusMac() != null) {
1308 radiusMacAddress = newCfg.radiusMac();
1309 }
1310 if (newCfg.nasMac() != null) {
1311 nasMacAddress = newCfg.nasMac();
1312 }
Andrea Campanellac4781e62020-10-08 12:58:45 +02001313 if (newCfg.radiusSecret() != null && !newCfg.radiusSecret().equals(radiusSecret)) {
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001314 radiusSecret = newCfg.radiusSecret();
Andrea Campanellac4781e62020-10-08 12:58:45 +02001315 radiusOperationalStatusService.initialize(nasIpAddress.getAddress(), radiusSecret, impl);
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001316 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +01001317
Deepa Vaddireddye0e10722017-09-27 05:00:10 +05301318 boolean reconfigureCustomizer = false;
1319 if (customizer == null || !customizer.equals(newCfg.radiusPktCustomizer())) {
1320 customizer = newCfg.radiusPktCustomizer();
1321 configurePacketCustomizer();
1322 reconfigureCustomizer = true;
1323 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +01001324
Deepa Vaddireddye0e10722017-09-27 05:00:10 +05301325 if (radiusConnectionType == null
1326 || reconfigureCustomizer
1327 || !radiusConnectionType.equals(newCfg.radiusConnectionType())) {
1328 radiusConnectionType = newCfg.radiusConnectionType();
1329 if (impl != null) {
1330 impl.withdrawIntercepts();
1331 impl.clearLocalState();
1332 }
Ilayda Ozdemir9fdeee72021-02-26 12:24:27 +00001333 configureRadiusCommunication(false);
Deepa Vaddireddye0e10722017-09-27 05:00:10 +05301334 impl.initializeLocalState(newCfg);
1335 impl.requestIntercepts();
1336 } else if (impl != null) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +01001337 impl.clearLocalState();
1338 impl.initializeLocalState(newCfg);
Ray Milkey5d99bd12015-10-06 15:41:30 -07001339 }
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001340 }
1341
1342 @Override
1343 public void event(NetworkConfigEvent event) {
1344
1345 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
1346 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
Jonathan Hart092dfb22015-11-16 23:05:21 -08001347 event.configClass().equals(AaaConfig.class)) {
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001348
Jonathan Hart092dfb22015-11-16 23:05:21 -08001349 AaaConfig cfg = netCfgService.getConfig(appId, AaaConfig.class);
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001350 reconfigureNetwork(cfg);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +01001351
Matt Jeanneret2ff1a782018-06-13 15:24:25 -04001352 log.info("Reconfigured: {}", cfg.toString());
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001353 }
1354 }
1355 }
Amit Ghoshf739be52017-09-21 15:49:37 +01001356
Jonathan Hart9d1ce802020-01-28 10:45:08 -08001357 private class InternalMapEventListener implements MapEventListener<ConnectPoint, AuthenticationRecord> {
1358 @Override
1359 public void event(MapEvent<ConnectPoint, AuthenticationRecord> event) {
1360 if (event.type() == MapEvent.Type.REMOVE) {
1361 // remove local state machine if user has requested remove
Andrea Campanellad8023322021-03-22 17:40:39 +01001362 StateMachine sm = stateMachines.remove(event.key().toString());
Jonathan Hart9d1ce802020-01-28 10:45:08 -08001363 if (sm != null) {
1364 sm.stop();
1365 }
1366 }
1367 }
1368 }
1369
Amit Ghoshf739be52017-09-21 15:49:37 +01001370 private class InternalDeviceListener implements DeviceListener {
1371 @Override
1372 public void event(DeviceEvent event) {
Andrea Campanellabba33672020-02-11 14:03:01 +01001373 DeviceId deviceId = event.subject().id();
Andrea Campanellad8023322021-03-22 17:40:39 +01001374 log.debug("AAA received device event {} ", event);
Amit Ghoshf739be52017-09-21 15:49:37 +01001375 switch (event.type()) {
1376 case PORT_REMOVED:
Amit Ghoshf739be52017-09-21 15:49:37 +01001377 PortNumber portNumber = event.port().number();
Andrea Campanellad8023322021-03-22 17:40:39 +01001378 String sessionId = deviceId.toString() + "/" + portNumber.toString();
Girish Kumar064084c2020-02-04 08:32:46 +00001379 log.debug("Received PORT_REMOVED event. Clearing AAA Session with Id {}", sessionId);
Hardik Windlass75c67712020-02-21 10:57:20 +00001380
Girish Kumar064084c2020-02-04 08:32:46 +00001381 flushStateMachineSession(sessionId,
Matteo Scandoloe033c262020-10-14 11:37:39 -07001382 StateMachine.SessionTerminationReasons.PORT_REMOVED.getReason());
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +00001383
Girish Kumar064084c2020-02-04 08:32:46 +00001384 break;
Girish Kumar064084c2020-02-04 08:32:46 +00001385 case DEVICE_REMOVED:
Girish Kumar064084c2020-02-04 08:32:46 +00001386 log.debug("Received DEVICE_REMOVED event for {}", deviceId);
Andrea Campanellabba33672020-02-11 14:03:01 +01001387 clearAllSessionStateForDevice(deviceId);
Amit Ghoshf739be52017-09-21 15:49:37 +01001388 break;
Girish Kumar064084c2020-02-04 08:32:46 +00001389
Amit Ghoshf739be52017-09-21 15:49:37 +01001390 default:
1391 return;
1392 }
1393 }
Girish Kumar064084c2020-02-04 08:32:46 +00001394
Andrea Campanellabba33672020-02-11 14:03:01 +01001395 private void clearAllSessionStateForDevice(DeviceId deviceId) {
1396 Set<String> associatedSessions = Sets.newHashSet();
1397 for (Entry<String, StateMachine> stateMachineEntry : stateMachines.entrySet()) {
1398 ConnectPoint cp = stateMachineEntry.getValue().supplicantConnectpoint();
1399 if (cp != null && cp.deviceId().toString().equals(deviceId.toString())) {
1400 associatedSessions.add(stateMachineEntry.getKey());
1401 }
1402 }
1403
1404 for (String session : associatedSessions) {
1405 log.debug("Clearing AAA Session {} associated with Removed Device", session);
1406 flushStateMachineSession(session,
Matteo Scandoloe033c262020-10-14 11:37:39 -07001407 StateMachine.SessionTerminationReasons.DEVICE_REMOVED.getReason());
Andrea Campanellabba33672020-02-11 14:03:01 +01001408 }
1409 }
1410
Girish Kumar064084c2020-02-04 08:32:46 +00001411 private void flushStateMachineSession(String sessionId, String terminationReason) {
1412 StateMachine stateMachine = stateMachines.get(sessionId);
Andrea Campanellad8023322021-03-22 17:40:39 +01001413 //flushing the state machine state requires also to remove the authenticated user.
1414 //the removal of the user might happen once the state machine is gone (app update)
1415 authentications.remove(ConnectPoint.fromString(sessionId));
1416
Girish Kumare5a1aa92020-02-14 14:08:54 +00001417 if (stateMachine == null) {
1418 // No active AAA sessions for this UNI port
1419 log.debug("No Active AAA Session found with Id {}", sessionId);
1420 return;
Girish Kumar064084c2020-02-04 08:32:46 +00001421 }
1422
Girish Kumare5a1aa92020-02-14 14:08:54 +00001423 stateMachine.setSessionTerminateReason(terminationReason);
1424
Girish Kumar064084c2020-02-04 08:32:46 +00001425 //pushing captured machine stats to kafka
1426 AaaSupplicantMachineStats obj = aaaSupplicantStatsManager.getSupplicantStats(stateMachine);
1427 aaaSupplicantStatsManager.getMachineStatsDelegate()
Matteo Scandoloe033c262020-10-14 11:37:39 -07001428 .notify(new AaaMachineStatisticsEvent(AaaMachineStatisticsEvent.Type.STATS_UPDATE, obj));
Girish Kumar064084c2020-02-04 08:32:46 +00001429 StateMachine removed = stateMachines.remove(sessionId);
Shubham Sharma8d7a9822020-01-28 10:04:01 +00001430
Girish Kumar064084c2020-02-04 08:32:46 +00001431 if (removed != null) {
1432 StateMachine.deleteStateMachineMapping(removed);
1433 }
1434 }
Amit Ghoshf739be52017-09-21 15:49:37 +01001435 }
Girish Kumar064084c2020-02-04 08:32:46 +00001436
Shubham Sharma4900ce62019-06-19 14:18:50 +00001437 private class ServerStatusChecker implements Runnable {
1438 @Override
1439 public void run() {
Matteo Scandolo3498bc02020-01-08 09:54:12 -08001440 log.debug("Notifying RadiusOperationalStatusEvent");
Shubham Sharma4900ce62019-06-19 14:18:50 +00001441 radiusOperationalStatusService.checkServerOperationalStatus();
Matteo Scandolo3498bc02020-01-08 09:54:12 -08001442 log.trace("--POSTING--" + radiusOperationalStatusService.getRadiusServerOperationalStatus());
Shubham Sharma4900ce62019-06-19 14:18:50 +00001443 radiusOperationalStatusService.getRadiusOprStDelegate()
Matteo Scandoloe033c262020-10-14 11:37:39 -07001444 .notify(new RadiusOperationalStatusEvent(
1445 RadiusOperationalStatusEvent.Type.RADIUS_OPERATIONAL_STATUS,
1446 radiusOperationalStatusService.
1447 getRadiusServerOperationalStatus()));
kartikey dubeye1545422019-05-22 12:53:45 +00001448 }
Shubham Sharma4900ce62019-06-19 14:18:50 +00001449
1450 }
Shubham Sharma544ffa22020-02-13 06:41:02 +00001451
1452 @Override
1453 public AaaSupplicantMachineStats getSupplicantMachineStats(String sessionId) {
1454 StateMachine aaaSupplicantMachine = stateMachines.get(sessionId);
1455 if (aaaSupplicantMachine != null) {
1456 return aaaSupplicantStatsManager.getSupplicantStats(aaaSupplicantMachine);
1457 } else {
1458 return null;
1459 }
1460 }
Jonathan Hart612651f2019-11-25 09:21:43 -08001461}