blob: 2f1a7e58b06e6951706298802ec48523eb95da59 [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;
28import java.net.InetAddress;
29import java.net.UnknownHostException;
30import java.nio.ByteBuffer;
31import java.util.Dictionary;
32import java.util.HashSet;
33import java.util.Arrays;
34import java.util.List;
Hardik Windlassd0b49692020-02-26 18:17:14 +000035import java.util.Map;
Girish Kumar064084c2020-02-04 08:32:46 +000036import java.util.Set;
37import java.util.Map.Entry;
38
Jonathan Hart932bedc2018-07-12 13:46:09 -070039import org.apache.commons.lang3.builder.ToStringBuilder;
Jonathan Hart4731dd92018-05-02 17:30:05 -070040import org.onlab.packet.DeserializationException;
Jonathan Harta46dddf2015-06-30 15:31:20 -070041import org.onlab.packet.EAP;
42import org.onlab.packet.EAPOL;
43import org.onlab.packet.EthType;
Ari Saha89831742015-06-26 10:31:48 -070044import org.onlab.packet.Ethernet;
Ari Saha89831742015-06-26 10:31:48 -070045import org.onlab.packet.MacAddress;
Jonathan Harta46dddf2015-06-30 15:31:20 -070046import org.onlab.packet.RADIUS;
47import org.onlab.packet.RADIUSAttribute;
Jonathan Hart9d1ce802020-01-28 10:45:08 -080048import org.onlab.util.KryoNamespace;
kartikey dubeye1545422019-05-22 12:53:45 +000049import org.onlab.util.Tools;
50import org.onosproject.cfg.ComponentConfigService;
Ari Saha89831742015-06-26 10:31:48 -070051import org.onosproject.core.ApplicationId;
52import org.onosproject.core.CoreService;
Jonathan Hart5db44532018-07-12 18:13:54 -070053import org.onosproject.event.AbstractListenerManager;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010054import org.onosproject.mastership.MastershipService;
Ari Saha89831742015-06-26 10:31:48 -070055import org.onosproject.net.ConnectPoint;
56import org.onosproject.net.DeviceId;
Ari Saha89831742015-06-26 10:31:48 -070057import org.onosproject.net.PortNumber;
Ray Milkeyfcb623d2015-10-01 16:48:18 -070058import org.onosproject.net.config.ConfigFactory;
59import org.onosproject.net.config.NetworkConfigEvent;
60import org.onosproject.net.config.NetworkConfigListener;
61import org.onosproject.net.config.NetworkConfigRegistry;
Amit Ghoshf739be52017-09-21 15:49:37 +010062import org.onosproject.net.device.DeviceEvent;
63import org.onosproject.net.device.DeviceListener;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010064import org.onosproject.net.device.DeviceService;
Ari Saha89831742015-06-26 10:31:48 -070065import org.onosproject.net.flow.DefaultTrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070066import org.onosproject.net.flow.TrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070067import org.onosproject.net.packet.DefaultOutboundPacket;
68import org.onosproject.net.packet.InboundPacket;
69import org.onosproject.net.packet.OutboundPacket;
70import org.onosproject.net.packet.PacketContext;
Ari Saha89831742015-06-26 10:31:48 -070071import org.onosproject.net.packet.PacketProcessor;
72import org.onosproject.net.packet.PacketService;
Jonathan Hartc41227c2020-01-28 16:56:49 -080073import org.onosproject.store.serializers.KryoNamespaces;
Jonathan Hart9d1ce802020-01-28 10:45:08 -080074import org.onosproject.store.service.ConsistentMap;
75import org.onosproject.store.service.MapEvent;
76import org.onosproject.store.service.MapEventListener;
77import org.onosproject.store.service.Serializer;
78import org.onosproject.store.service.StorageService;
Matteo Scandolocf847b82019-04-26 15:00:00 -070079import org.opencord.aaa.AaaConfig;
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +000080import org.opencord.aaa.AaaMachineStatisticsEvent;
81import org.opencord.aaa.AaaMachineStatisticsService;
82import org.opencord.aaa.AaaSupplicantMachineStats;
Matteo Scandolocf847b82019-04-26 15:00:00 -070083import org.opencord.aaa.AuthenticationEvent;
84import org.opencord.aaa.AuthenticationEventListener;
Jonathan Hart612651f2019-11-25 09:21:43 -080085import org.opencord.aaa.AuthenticationRecord;
Matteo Scandolocf847b82019-04-26 15:00:00 -070086import org.opencord.aaa.AuthenticationService;
kartikey dubeye1545422019-05-22 12:53:45 +000087import org.opencord.aaa.AuthenticationStatisticsService;
Matteo Scandolocf847b82019-04-26 15:00:00 -070088import org.opencord.aaa.RadiusCommunicator;
Shubham Sharma4900ce62019-06-19 14:18:50 +000089import org.opencord.aaa.RadiusOperationalStatusEvent;
90import org.opencord.aaa.RadiusOperationalStatusService;
91import org.opencord.aaa.RadiusOperationalStatusService.RadiusOperationalStatusEvaluationMode;
Matteo Scandolocf847b82019-04-26 15:00:00 -070092import org.opencord.aaa.StateMachineDelegate;
Gamze Abaka1cfdb192018-10-25 11:39:19 +000093import org.opencord.sadis.BaseInformationService;
94import org.opencord.sadis.SadisService;
95import org.opencord.sadis.SubscriberAndDeviceInformation;
kartikey dubeye1545422019-05-22 12:53:45 +000096import org.osgi.service.component.ComponentContext;
Carmelo Cascone58b53292019-09-30 12:35:31 -070097import org.osgi.service.component.annotations.Activate;
Shubham Sharma4900ce62019-06-19 14:18:50 +000098import org.osgi.service.component.annotations.Component;
99import org.osgi.service.component.annotations.Deactivate;
100import org.osgi.service.component.annotations.Modified;
101import org.osgi.service.component.annotations.Reference;
102import org.osgi.service.component.annotations.ReferenceCardinality;
Ari Saha89831742015-06-26 10:31:48 -0700103import org.slf4j.Logger;
104
Shubham Sharma4900ce62019-06-19 14:18:50 +0000105import javax.crypto.Mac;
106import javax.crypto.spec.SecretKeySpec;
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800107import java.util.Optional;
Jonathan Hart612651f2019-11-25 09:21:43 -0800108import java.util.concurrent.ConcurrentMap;
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700109import java.util.concurrent.ExecutorService;
kartikey dubeye1545422019-05-22 12:53:45 +0000110import java.util.concurrent.Executors;
111import java.util.concurrent.ScheduledExecutorService;
112import java.util.concurrent.ScheduledFuture;
113import java.util.concurrent.TimeUnit;
Vijaykumar Kushwaha056e4cd2019-08-06 13:16:25 +0000114
Ari Saha89831742015-06-26 10:31:48 -0700115/**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700116 * AAA application for ONOS.
Ari Saha89831742015-06-26 10:31:48 -0700117 */
Carmelo Cascone58b53292019-09-30 12:35:31 -0700118@Component(immediate = true, property = {
Shubham Sharma4900ce62019-06-19 14:18:50 +0000119 OPERATIONAL_STATUS_SERVER_EVENT_GENERATION + ":Integer=" + OPERATIONAL_STATUS_SERVER_EVENT_GENERATION_DEFAULT,
120 OPERATIONAL_STATUS_SERVER_TIMEOUT + ":Integer=" + OPERATIONAL_STATUS_SERVER_TIMEOUT_DEFAULT,
121 STATUS_SERVER_MODE + ":String=" + STATUS_SERVER_MODE_DEFAULT,
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700122 PACKET_PROCESSOR_THREADS + ":Integer=" + PACKET_PROCESSOR_THREADS_DEFAULT,
Carmelo Cascone58b53292019-09-30 12:35:31 -0700123})
Jonathan Hart5db44532018-07-12 18:13:54 -0700124public class AaaManager
125 extends AbstractListenerManager<AuthenticationEvent, AuthenticationEventListener>
126 implements AuthenticationService {
127
Charles Chandf7ff862017-01-20 11:22:05 -0800128 private static final String APP_NAME = "org.opencord.aaa";
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700129 private static final int STATE_MACHINE_THREADS = 3;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700130
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700131 private final Logger log = getLogger(getClass());
Ray Milkeyf51eba22015-09-25 10:24:23 -0700132
Carmelo Cascone58b53292019-09-30 12:35:31 -0700133 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700134 protected CoreService coreService;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700135
Carmelo Cascone58b53292019-09-30 12:35:31 -0700136 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800137 protected StorageService storageService;
138
139 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700140 protected PacketService packetService;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700141
Carmelo Cascone58b53292019-09-30 12:35:31 -0700142 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700143 protected NetworkConfigRegistry netCfgService;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700144
Carmelo Cascone58b53292019-09-30 12:35:31 -0700145 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100146 protected DeviceService deviceService;
147
Carmelo Cascone58b53292019-09-30 12:35:31 -0700148 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Gamze Abaka1cfdb192018-10-25 11:39:19 +0000149 protected SadisService sadisService;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100150
Carmelo Cascone58b53292019-09-30 12:35:31 -0700151 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100152 protected MastershipService mastershipService;
153
Carmelo Cascone58b53292019-09-30 12:35:31 -0700154 @Reference(cardinality = ReferenceCardinality.MANDATORY)
kartikey dubeye1545422019-05-22 12:53:45 +0000155 protected AuthenticationStatisticsService aaaStatisticsManager;
Gamze Abaka1cfdb192018-10-25 11:39:19 +0000156
Carmelo Cascone58b53292019-09-30 12:35:31 -0700157 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +0000158 protected AaaMachineStatisticsService aaaSupplicantStatsManager;
159
160 @Reference(cardinality = ReferenceCardinality.MANDATORY)
kartikey dubeye1545422019-05-22 12:53:45 +0000161 protected ComponentConfigService cfgService;
162
Shubham Sharma4900ce62019-06-19 14:18:50 +0000163 @Reference(cardinality = ReferenceCardinality.MANDATORY)
164 protected RadiusOperationalStatusService radiusOperationalStatusService;
165
kartikey dubeye1545422019-05-22 12:53:45 +0000166 protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
Amit Ghoshf739be52017-09-21 15:49:37 +0100167 private final DeviceListener deviceListener = new InternalDeviceListener();
168
Shubham Sharma4900ce62019-06-19 14:18:50 +0000169 // Properties
Shubham Sharma4900ce62019-06-19 14:18:50 +0000170 private int operationalStatusEventGenerationPeriodInSeconds = OPERATIONAL_STATUS_SERVER_EVENT_GENERATION_DEFAULT;
171 private int operationalStatusServerTimeoutInSeconds = OPERATIONAL_STATUS_SERVER_TIMEOUT_DEFAULT;
172 protected String operationalStatusEvaluationMode = STATUS_SERVER_MODE_DEFAULT;
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700173 /**
174 * Number of threads used to process the packet.
175 */
176 protected int packetProcessorThreads = PACKET_PROCESSOR_THREADS_DEFAULT;
kartikey dubeye1545422019-05-22 12:53:45 +0000177
Jonathan Hart612651f2019-11-25 09:21:43 -0800178 private IdentifierManager idManager;
179
180 private ConcurrentMap<String, StateMachine> stateMachines;
181
Hardik Windlassd0b49692020-02-26 18:17:14 +0000182 private ConsistentMap<ConnectPoint, AuthenticationRecord> authenticationsConsistentMap;
183 private Map<ConnectPoint, AuthenticationRecord> authentications;
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800184
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700185 // NAS IP address
186 protected InetAddress nasIpAddress;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100187
188 // self MAC address
Jonathan Hart5db44532018-07-12 18:13:54 -0700189 protected String nasMacAddress;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100190
191 // Parsed RADIUS server addresses
192 protected InetAddress radiusIpAddress;
193
194 // MAC address of RADIUS server or net hop router
195 protected String radiusMacAddress;
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700196
197 // RADIUS server secret
198 protected String radiusSecret;
199
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100200 // bindings
201 protected CustomizationInfo customInfo;
Ray Milkey5d99bd12015-10-06 15:41:30 -0700202
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700203 // our application-specific event handler
204 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
Ray Milkeyf51eba22015-09-25 10:24:23 -0700205
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700206 // our unique identifier
207 private ApplicationId appId;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700208
Shubham Sharma1e43c562019-06-19 14:18:12 +0000209 // TimeOut time for cleaning up stateMachines stuck due to pending AAA/EAPOL message.
210 protected int cleanupTimerTimeOutInMins;
211
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100212 // Setup specific customization/attributes on the RADIUS packets
213 PacketCustomizer pktCustomizer;
Ray Milkey967776a2015-10-07 14:37:17 -0700214
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100215 // packet customizer to use
216 private String customizer;
217
218 // Type of connection to use to communicate with Radius server, options are
219 // "socket" or "packet_out"
220 private String radiusConnectionType;
221
Jonathan Hart5db44532018-07-12 18:13:54 -0700222 // Object for the specific type of communication with the RADIUS
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100223 // server, socket based or packet_out based
224 RadiusCommunicator impl = null;
225
226 // latest configuration
227 AaaConfig newCfg;
Ray Milkey967776a2015-10-07 14:37:17 -0700228
Shubham Sharma4900ce62019-06-19 14:18:50 +0000229 ScheduledFuture<?> scheduledStatusServerChecker;
kartikey dubeye1545422019-05-22 12:53:45 +0000230 String configuredAaaServerAddress;
Jonathan Hartc41227c2020-01-28 16:56:49 -0800231 HashSet<Byte> outPacketSet = new HashSet<>();
232 HashSet<Byte> outPacketSupp = new HashSet<>();
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000233 static final List<Byte> VALID_EAPOL_TYPE = Arrays.asList(EAPOL.EAPOL_START, EAPOL.EAPOL_LOGOFF, EAPOL.EAPOL_PACKET);
234 static final int HEADER_LENGTH = 4;
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700235 // Configuration properties factory
236 private final ConfigFactory factory =
Jonathan Hart092dfb22015-11-16 23:05:21 -0800237 new ConfigFactory<ApplicationId, AaaConfig>(APP_SUBJECT_FACTORY,
238 AaaConfig.class,
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700239 "AAA") {
240 @Override
Jonathan Hart092dfb22015-11-16 23:05:21 -0800241 public AaaConfig createConfig() {
242 return new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700243 }
244 };
Ray Milkeyf51eba22015-09-25 10:24:23 -0700245
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700246 // Listener for config changes
247 private final InternalConfigListener cfgListener = new InternalConfigListener();
Ari Saha89831742015-06-26 10:31:48 -0700248
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800249 private final InternalMapEventListener mapListener = new InternalMapEventListener();
250
Jonathan Hart5db44532018-07-12 18:13:54 -0700251 private StateMachineDelegate delegate = new InternalStateMachineDelegate();
252
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700253 protected ExecutorService packetProcessorExecutor;
254 protected ScheduledExecutorService serverStatusAndStateMachineTimeoutExecutor;
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700255 /**
256 * Builds an EAPOL packet based on the given parameters.
257 *
258 * @param dstMac destination MAC address
259 * @param srcMac source MAC address
260 * @param vlan vlan identifier
261 * @param eapolType EAPOL type
262 * @param eap EAP payload
263 * @return Ethernet frame
264 */
265 private static Ethernet buildEapolResponse(MacAddress dstMac, MacAddress srcMac,
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100266 short vlan, byte eapolType, EAP eap, byte priorityCode) {
Ari Saha89831742015-06-26 10:31:48 -0700267
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700268 Ethernet eth = new Ethernet();
269 eth.setDestinationMACAddress(dstMac.toBytes());
270 eth.setSourceMACAddress(srcMac.toBytes());
271 eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
272 if (vlan != Ethernet.VLAN_UNTAGGED) {
273 eth.setVlanID(vlan);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100274 eth.setPriorityCode(priorityCode);
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700275 }
276 //eapol header
277 EAPOL eapol = new EAPOL();
278 eapol.setEapolType(eapolType);
279 eapol.setPacketLength(eap.getLength());
Ari Saha89831742015-06-26 10:31:48 -0700280
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700281 //eap part
282 eapol.setPayload(eap);
283
284 eth.setPayload(eapol);
285 eth.setPad(true);
286 return eth;
287 }
Ari Saha89831742015-06-26 10:31:48 -0700288
Ari Saha89831742015-06-26 10:31:48 -0700289 @Activate
kartikey dubeye1545422019-05-22 12:53:45 +0000290 public void activate(ComponentContext context) {
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700291
Jonathan Hart612651f2019-11-25 09:21:43 -0800292 idManager = new IdentifierManager();
293 stateMachines = Maps.newConcurrentMap();
Charles Chandf7ff862017-01-20 11:22:05 -0800294 appId = coreService.registerApplication(APP_NAME);
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800295
296 KryoNamespace authSerializer = KryoNamespace.newBuilder()
Jonathan Hartc41227c2020-01-28 16:56:49 -0800297 .register(KryoNamespaces.API)
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800298 .register(AuthenticationRecord.class)
299 .build();
300
Hardik Windlassd0b49692020-02-26 18:17:14 +0000301 authenticationsConsistentMap = storageService.<ConnectPoint, AuthenticationRecord>consistentMapBuilder()
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800302 .withApplicationId(appId)
303 .withName("authentications")
304 .withSerializer(Serializer.using(authSerializer))
305 .build();
Hardik Windlassd0b49692020-02-26 18:17:14 +0000306 authenticationsConsistentMap.addListener(mapListener);
307 authentications = authenticationsConsistentMap.asJavaMap();
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800308
Jonathan Hart5db44532018-07-12 18:13:54 -0700309 eventDispatcher.addSink(AuthenticationEvent.class, listenerRegistry);
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400310 netCfgService.addListener(cfgListener);
311 netCfgService.registerConfigFactory(factory);
kartikey dubeye1545422019-05-22 12:53:45 +0000312 cfgService.registerProperties(getClass());
313 modified(context);
Gamze Abaka1cfdb192018-10-25 11:39:19 +0000314 subsService = sadisService.getSubscriberInfoService();
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530315 customInfo = new CustomizationInfo(subsService, deviceService);
Jonathan Hart092dfb22015-11-16 23:05:21 -0800316 cfgListener.reconfigureNetwork(netCfgService.getConfig(appId, AaaConfig.class));
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400317 log.info("Starting with config {} {}", this, newCfg);
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530318 configureRadiusCommunication();
Ari Saha89831742015-06-26 10:31:48 -0700319 // register our event handler
Brian O'Connord9c7da02015-07-29 17:49:24 -0700320 packetService.addProcessor(processor, PacketProcessor.director(2));
Jonathan Hart5db44532018-07-12 18:13:54 -0700321 StateMachine.setDelegate(delegate);
Shubham Sharma1e43c562019-06-19 14:18:12 +0000322 cleanupTimerTimeOutInMins = newCfg.sessionCleanupTimer();
323 StateMachine.setcleanupTimerTimeOutInMins(cleanupTimerTimeOutInMins);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100324 impl.initializeLocalState(newCfg);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100325 impl.requestIntercepts();
Amit Ghoshf739be52017-09-21 15:49:37 +0100326 deviceService.addListener(deviceListener);
kartikey dubeye1545422019-05-22 12:53:45 +0000327 getConfiguredAaaServerAddress();
Shubham Sharma4900ce62019-06-19 14:18:50 +0000328 radiusOperationalStatusService.initialize(nasIpAddress.getAddress(), radiusSecret, impl);
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700329 serverStatusAndStateMachineTimeoutExecutor = Executors.newScheduledThreadPool(STATE_MACHINE_THREADS,
330 groupedThreads("onos/aaa", "aaa-machine-%d", log));
Shubham Sharma4900ce62019-06-19 14:18:50 +0000331
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700332 scheduledStatusServerChecker = serverStatusAndStateMachineTimeoutExecutor.scheduleAtFixedRate(
333 new ServerStatusChecker(), 0,
334 operationalStatusEventGenerationPeriodInSeconds, TimeUnit.SECONDS);
Amit Ghoshf739be52017-09-21 15:49:37 +0100335
Jian Li13c67162015-12-09 13:20:34 -0800336 log.info("Started");
Ari Saha89831742015-06-26 10:31:48 -0700337 }
338
339 @Deactivate
kartikey dubeye1545422019-05-22 12:53:45 +0000340 public void deactivate(ComponentContext context) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100341 impl.withdrawIntercepts();
Ari Saha89831742015-06-26 10:31:48 -0700342 packetService.removeProcessor(processor);
Deepa Vaddireddyb9c24c62017-09-21 13:45:30 +0530343 netCfgService.removeListener(cfgListener);
kartikey dubeye1545422019-05-22 12:53:45 +0000344 cfgService.unregisterProperties(getClass(), false);
Jonathan Hart5db44532018-07-12 18:13:54 -0700345 StateMachine.unsetDelegate(delegate);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100346 impl.deactivate();
Amit Ghoshf739be52017-09-21 15:49:37 +0100347 deviceService.removeListener(deviceListener);
Jonathan Hart5db44532018-07-12 18:13:54 -0700348 eventDispatcher.removeSink(AuthenticationEvent.class);
Shubham Sharma4900ce62019-06-19 14:18:50 +0000349 scheduledStatusServerChecker.cancel(true);
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700350 serverStatusAndStateMachineTimeoutExecutor.shutdown();
351 packetProcessorExecutor.shutdown();
Hardik Windlassd0b49692020-02-26 18:17:14 +0000352 authenticationsConsistentMap.removeListener(mapListener);
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800353
Jian Li13c67162015-12-09 13:20:34 -0800354 log.info("Stopped");
Ray Milkey967776a2015-10-07 14:37:17 -0700355 }
kartikey dubeye1545422019-05-22 12:53:45 +0000356 @Modified
357 public void modified(ComponentContext context) {
Shubham Sharma4900ce62019-06-19 14:18:50 +0000358 Dictionary<String, Object> properties = context.getProperties();
359
Jonathan Hartc41227c2020-01-28 16:56:49 -0800360 String s = Tools.get(properties, "operationalStatusEventGenerationPeriodInSeconds");
Shubham Sharma4900ce62019-06-19 14:18:50 +0000361 operationalStatusEventGenerationPeriodInSeconds = Strings.isNullOrEmpty(s)
362 ? OPERATIONAL_STATUS_SERVER_EVENT_GENERATION_DEFAULT
363 : Integer.parseInt(s.trim());
364
365 s = Tools.get(properties, "operationalStatusServerTimeoutInSeconds");
366 operationalStatusServerTimeoutInSeconds = Strings.isNullOrEmpty(s) ? OPERATIONAL_STATUS_SERVER_TIMEOUT_DEFAULT
367 : Integer.parseInt(s.trim());
368
369 s = Tools.get(properties, "operationalStatusEvaluationMode");
370 String newEvaluationModeString = Strings.isNullOrEmpty(s) ? STATUS_SERVER_MODE_DEFAULT : s.trim();
371
372 radiusOperationalStatusService
373 .setOperationalStatusServerTimeoutInMillis(operationalStatusServerTimeoutInSeconds * 1000);
374 RadiusOperationalStatusEvaluationMode newEvaluationMode =
375 RadiusOperationalStatusEvaluationMode.getValue(newEvaluationModeString);
376 if (newEvaluationMode != null) {
377 radiusOperationalStatusService.setRadiusOperationalStatusEvaluationMode(newEvaluationMode);
378 operationalStatusEvaluationMode = newEvaluationModeString;
379 } else {
380 properties.put("operationalStatusEvaluationMode", operationalStatusEvaluationMode);
381 }
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700382
383 s = Tools.get(properties, PACKET_PROCESSOR_THREADS);
384 int oldpacketProcessorThreads = packetProcessorThreads;
385 packetProcessorThreads = Strings.isNullOrEmpty(s) ? oldpacketProcessorThreads
386 : Integer.parseInt(s.trim());
387 if (packetProcessorExecutor == null || oldpacketProcessorThreads != packetProcessorThreads) {
388 if (packetProcessorExecutor != null) {
389 packetProcessorExecutor.shutdown();
390 }
Andrea Campanellac4781e62020-10-08 12:58:45 +0200391 packetProcessorExecutor = newSingleThreadExecutor(groupedThreads("onos/aaa", "aaa-packet-%d", log));
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700392
393 }
kartikey dubeye1545422019-05-22 12:53:45 +0000394 }
395
Shubham Sharmacf5e5032019-11-26 11:09:21 +0000396 protected void configureRadiusCommunication() {
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530397 if (radiusConnectionType.toLowerCase().equals("socket")) {
398 impl = new SocketBasedRadiusCommunicator(appId, packetService, this);
399 } else {
400 impl = new PortBasedRadiusCommunicator(appId, packetService, mastershipService,
401 deviceService, subsService, pktCustomizer, this);
402 }
403 }
404
405 private void configurePacketCustomizer() {
406 switch (customizer.toLowerCase()) {
407 case "sample":
408 pktCustomizer = new SamplePacketCustomizer(customInfo);
409 log.info("Created SamplePacketCustomizer");
410 break;
Saurav Dase72358a2018-11-13 21:56:46 -0800411 case "att":
412 pktCustomizer = new AttPacketCustomizer(customInfo);
413 log.info("Created AttPacketCustomizer");
414 break;
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530415 default:
416 pktCustomizer = new PacketCustomizer(customInfo);
417 log.info("Created default PacketCustomizer");
418 break;
419 }
420 }
421
kartikey dubeye1545422019-05-22 12:53:45 +0000422 private void getConfiguredAaaServerAddress() {
423 try {
424 InetAddress address;
425 if (newCfg.radiusHostName() != null) {
426 address = InetAddress.getByName(newCfg.radiusHostName());
427 } else {
428 address = newCfg.radiusIp();
429 }
430
431 configuredAaaServerAddress = address.getHostAddress();
432 } catch (UnknownHostException uhe) {
433 log.warn("Unable to resolve host {}", newCfg.radiusHostName());
434 }
435 }
436
Vijaykumar Kushwaha056e4cd2019-08-06 13:16:25 +0000437 private void checkReceivedPacketForValidValidator(RADIUS radiusPacket, byte[] requestAuthenticator) {
438 if (!checkResponseMessageAuthenticator(radiusSecret, radiusPacket, requestAuthenticator)) {
kartikey dubeye1545422019-05-22 12:53:45 +0000439 aaaStatisticsManager.getAaaStats().increaseInvalidValidatorsRx();
440 }
441 }
Vijaykumar Kushwaha056e4cd2019-08-06 13:16:25 +0000442
443 private boolean checkResponseMessageAuthenticator(String key, RADIUS radiusPacket, byte[] requestAuthenticator) {
444 byte[] newHash = new byte[16];
445 Arrays.fill(newHash, (byte) 0);
446 byte[] messageAuthenticator = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH).getValue();
447 byte[] authenticator = radiusPacket.getAuthenticator();
448 radiusPacket.updateAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH, newHash);
449 radiusPacket.setAuthenticator(requestAuthenticator);
450 // Calculate the MD5 HMAC based on the message
451 try {
452 SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "HmacMD5");
453 Mac mac = Mac.getInstance("HmacMD5");
454 mac.init(keySpec);
455 newHash = mac.doFinal(radiusPacket.serialize());
456 } catch (Exception e) {
457 log.error("Failed to generate message authenticator: {}", e.getMessage());
458 }
459 radiusPacket.updateAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH, messageAuthenticator);
460 radiusPacket.setAuthenticator(authenticator);
461 // Compare the calculated Message-Authenticator with the one in the message
462 return Arrays.equals(newHash, messageAuthenticator);
463 }
kartikey dubeye1545422019-05-22 12:53:45 +0000464 public void checkForPacketFromUnknownServer(String hostAddress) {
465 if (!hostAddress.equals(configuredAaaServerAddress)) {
Vijaykumar Kushwahafffd3d12019-08-01 11:09:59 +0000466 getConfiguredAaaServerAddress();
467 if (!hostAddress.equals(configuredAaaServerAddress)) {
468 aaaStatisticsManager.getAaaStats().incrementUnknownServerRx();
469 }
kartikey dubeye1545422019-05-22 12:53:45 +0000470 }
471 }
472
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100473 /**
474 * Send RADIUS packet to the RADIUS server.
475 *
476 * @param radiusPacket RADIUS packet to be sent to server.
477 * @param inPkt Incoming EAPOL packet
478 */
479 protected void sendRadiusPacket(RADIUS radiusPacket, InboundPacket inPkt) {
kartikey dubeye1545422019-05-22 12:53:45 +0000480 outPacketSet.add(radiusPacket.getIdentifier());
481 aaaStatisticsManager.getAaaStats().increaseOrDecreasePendingRequests(true);
482 aaaStatisticsManager.getAaaStats().increaseAccessRequestsTx();
Shubham Sharma4900ce62019-06-19 14:18:50 +0000483 aaaStatisticsManager.putOutgoingIdentifierToMap(radiusPacket.getIdentifier());
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100484 impl.sendRadiusPacket(radiusPacket, inPkt);
485 }
Ray Milkey967776a2015-10-07 14:37:17 -0700486
Jonathan Hart612651f2019-11-25 09:21:43 -0800487 /**
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100488 * Handles RADIUS packets.
489 *
490 * @param radiusPacket RADIUS packet coming from the RADIUS server.
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100491 */
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700492 public void handleRadiusPacket(RADIUS radiusPacket) {
Andrea Campanellac4781e62020-10-08 12:58:45 +0200493 if (log.isTraceEnabled()) {
494 log.trace("Received RADIUS packet {}", radiusPacket);
495 }
496 if (radiusOperationalStatusService.isRadiusResponseForOperationalStatus(radiusPacket.getIdentifier())) {
497 radiusOperationalStatusService.handleRadiusPacketForOperationalStatus(radiusPacket);
498 return;
499 }
Jonathan Hart612651f2019-11-25 09:21:43 -0800500
Andrea Campanellac4781e62020-10-08 12:58:45 +0200501 RequestIdentifier identifier = RequestIdentifier.of(radiusPacket.getIdentifier());
502 String sessionId = idManager.getSessionId(identifier);
Jonathan Hart612651f2019-11-25 09:21:43 -0800503
Andrea Campanellac4781e62020-10-08 12:58:45 +0200504 if (sessionId == null) {
505 log.error("Invalid packet identifier {}, could not find corresponding "
506 + "state machine ... exiting", radiusPacket.getIdentifier());
507 aaaStatisticsManager.getAaaStats().incrementNumberOfSessionsExpired();
508 aaaStatisticsManager.getAaaStats().countDroppedResponsesRx();
509 return;
510 }
Jonathan Hart612651f2019-11-25 09:21:43 -0800511
Andrea Campanellac4781e62020-10-08 12:58:45 +0200512 idManager.releaseIdentifier(identifier);
513 StateMachine stateMachine = stateMachines.get(sessionId);
514 if (stateMachine == null) {
515 log.error("Invalid packet identifier {}, could not find corresponding "
516 + "state machine ... exiting", radiusPacket.getIdentifier());
517 aaaStatisticsManager.getAaaStats().incrementNumberOfSessionsExpired();
518 aaaStatisticsManager.getAaaStats().countDroppedResponsesRx();
519 return;
520 }
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +0000521
Andrea Campanellac4781e62020-10-08 12:58:45 +0200522 //instance of StateMachine using the sessionId for updating machine stats
523 StateMachine machineStats = stateMachines.get(stateMachine.sessionId());
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +0000524
Andrea Campanellac4781e62020-10-08 12:58:45 +0200525 EAP eapPayload;
526 Ethernet eth;
527 checkReceivedPacketForValidValidator(radiusPacket, stateMachine.requestAuthenticator());
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +0000528
Andrea Campanellac4781e62020-10-08 12:58:45 +0200529 //increasing packets and octets received from server
530 machineStats.incrementTotalPacketsReceived();
531 try {
532 machineStats.incrementTotalOctetReceived(radiusPacket.decapsulateMessage().getLength());
533 } catch (DeserializationException e) {
534 log.error(e.getMessage());
535 return;
536 }
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700537
Andrea Campanellac4781e62020-10-08 12:58:45 +0200538 if (outPacketSet.contains(radiusPacket.getIdentifier())) {
539 aaaStatisticsManager.getAaaStats().increaseOrDecreasePendingRequests(false);
540 outPacketSet.remove(new Byte(radiusPacket.getIdentifier()));
541 }
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700542
Andrea Campanellac4781e62020-10-08 12:58:45 +0200543 MacAddress dstMac = stateMachine.supplicantAddress();
544 ConnectPoint supplicantCp = stateMachine.supplicantConnectpoint();
545 switch (radiusPacket.getCode()) {
546 case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE:
547 log.debug("RADIUS packet: RADIUS_CODE_ACCESS_CHALLENGE for dev/port: {}/{} with MacAddress {}",
548 supplicantCp.deviceId(), supplicantCp.port(), dstMac);
549 RADIUSAttribute radiusAttrState = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE);
550 byte[] challengeState = null;
551 if (radiusAttrState != null) {
552 challengeState = radiusAttrState.getValue();
553 }
554 try {
555 eapPayload = radiusPacket.decapsulateMessage();
556 eth = buildEapolResponse(stateMachine.supplicantAddress(),
557 MacAddress.valueOf(nasMacAddress),
558 stateMachine.vlanId(),
559 EAPOL.EAPOL_PACKET,
560 eapPayload, stateMachine.priorityCode());
561 stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState);
562 } catch (DeserializationException e) {
563 log.error(e.getMessage());
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700564 break;
Andrea Campanellac4781e62020-10-08 12:58:45 +0200565 }
566 log.debug("Send EAP challenge response to supplicant {} on dev/port: {}/{} with MacAddress {}",
567 supplicantCp.deviceId(), supplicantCp.port(), dstMac);
568 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint(), true);
569 aaaStatisticsManager.getAaaStats().increaseChallengeResponsesRx();
570 outPacketSupp.add(eapPayload.getIdentifier());
Andrea Campanella76ae68d2020-10-14 11:16:37 +0200571 aaaStatisticsManager.getAaaStats().incrementPendingReqSupp();
Andrea Campanellac4781e62020-10-08 12:58:45 +0200572 //increasing packets send to server
573 machineStats.incrementTotalPacketsSent();
574 machineStats.incrementTotalOctetSent(eapPayload.getLength());
575 break;
576 case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
577 log.debug("RADIUS packet: RADIUS_CODE_ACCESS_ACCEPT for dev/port: {}/{} with MacAddress {}",
578 supplicantCp.deviceId(), supplicantCp.port(), dstMac);
579 //send an EAPOL - Success to the supplicant.
580 byte[] eapMessageSuccess =
581 radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
582 try {
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700583 eapPayload = EAP.deserializer().deserialize(
584 eapMessageSuccess, 0, eapMessageSuccess.length);
Andrea Campanellac4781e62020-10-08 12:58:45 +0200585 } catch (DeserializationException e) {
586 log.error(e.getMessage());
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700587 break;
Andrea Campanellac4781e62020-10-08 12:58:45 +0200588 }
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700589
Andrea Campanellac4781e62020-10-08 12:58:45 +0200590 eth = buildEapolResponse(stateMachine.supplicantAddress(),
591 MacAddress.valueOf(nasMacAddress),
592 stateMachine.vlanId(),
593 EAPOL.EAPOL_PACKET,
594 eapPayload, stateMachine.priorityCode());
595 log.info("Send EAP success message to supplicant {} on dev/port: {}/{} with MacAddress {}",
596 supplicantCp.deviceId(), supplicantCp.port(), dstMac);
597 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint(), false);
598 aaaStatisticsManager.getAaaStats().incrementEapolAuthSuccessTrans();
599
600 stateMachine.authorizeAccess();
601 aaaStatisticsManager.getAaaStats().increaseAcceptResponsesRx();
602 //increasing packets send to server
603 machineStats.incrementTotalPacketsSent();
604 machineStats.incrementTotalOctetSent(eapPayload.getLength());
605 break;
606 case RADIUS.RADIUS_CODE_ACCESS_REJECT:
607 log.debug("RADIUS packet: RADIUS_CODE_ACCESS_REJECT for dev/port: {}/{} with MacAddress {}",
608 supplicantCp.deviceId(), supplicantCp.port(), dstMac);
609 //send an EAPOL - Failure to the supplicant.
610 byte[] eapMessageFailure;
611 eapPayload = new EAP();
612 RADIUSAttribute radiusAttrEap = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE);
613 if (radiusAttrEap == null) {
614 eapPayload.setCode(EAP.FAILURE);
615 eapPayload.setIdentifier(stateMachine.challengeIdentifier());
616 eapPayload.setLength(EAP.EAP_HDR_LEN_SUC_FAIL);
617 } else {
618 eapMessageFailure = radiusAttrEap.getValue();
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700619 try {
Andrea Campanellac4781e62020-10-08 12:58:45 +0200620 eapPayload = EAP.deserializer().deserialize(
621 eapMessageFailure, 0, eapMessageFailure.length);
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700622 } catch (DeserializationException e) {
623 log.error(e.getMessage());
624 break;
625 }
Andrea Campanellac4781e62020-10-08 12:58:45 +0200626 }
627 eth = buildEapolResponse(stateMachine.supplicantAddress(),
628 MacAddress.valueOf(nasMacAddress),
629 stateMachine.vlanId(),
630 EAPOL.EAPOL_PACKET,
631 eapPayload, stateMachine.priorityCode());
632 log.warn("Send EAP failure message to supplicant {} on dev/port: {}/{} with MacAddress {}",
633 supplicantCp.deviceId(), supplicantCp.port(), dstMac);
634 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint(), false);
635 aaaStatisticsManager.getAaaStats().incrementEapolauthFailureTrans();
636
637 stateMachine.denyAccess();
638 aaaStatisticsManager.getAaaStats().increaseRejectResponsesRx();
639 //increasing packets send to server
640 machineStats.incrementTotalPacketsSent();
641 machineStats.incrementTotalOctetSent(eapPayload.getLength());
642 //pushing machine stats to kafka
643 AaaSupplicantMachineStats machineObj = aaaSupplicantStatsManager.getSupplicantStats(machineStats);
644 aaaSupplicantStatsManager.getMachineStatsDelegate()
645 .notify(new AaaMachineStatisticsEvent(AaaMachineStatisticsEvent.Type.STATS_UPDATE,
646 machineObj));
647 break;
648 default:
649 log.warn("Unknown RADIUS message received with code: {} for dev/port: {}/{} with MacAddress {}",
650 radiusPacket.getCode(), supplicantCp.deviceId(), supplicantCp.port(), dstMac);
651 aaaStatisticsManager.getAaaStats().increaseUnknownTypeRx();
652 //increasing packets received to server
653 machineStats.incrementTotalPacketsReceived();
654 try {
655 machineStats.incrementTotalOctetReceived(radiusPacket.decapsulateMessage().getLength());
656 } catch (DeserializationException e) {
657 log.error(e.getMessage());
658 break;
659 }
660 }
661 aaaStatisticsManager.getAaaStats().countDroppedResponsesRx();
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700662 }
663
Ray Milkey967776a2015-10-07 14:37:17 -0700664 /**
665 * Send the ethernet packet to the supplicant.
666 *
667 * @param ethernetPkt the ethernet packet
668 * @param connectPoint the connect point to send out
669 */
Shubham Sharma1f193582019-07-11 12:12:41 +0000670 private void sendPacketToSupplicant(Ethernet ethernetPkt, ConnectPoint connectPoint, boolean isChallengeResponse) {
Ray Milkey967776a2015-10-07 14:37:17 -0700671 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
672 OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(),
673 treatment, ByteBuffer.wrap(ethernetPkt.serialize()));
Shubham Sharma1f193582019-07-11 12:12:41 +0000674 EAPOL eap = ((EAPOL) ethernetPkt.getPayload());
Saurav Das987441a2018-09-18 16:33:47 -0700675 if (log.isTraceEnabled()) {
Andrea Campanellac4781e62020-10-08 12:58:45 +0200676 log.trace("Sending eapol payload {} enclosed in {} to supplicant at {} with MacAddress {}",
677 eap, ethernetPkt, connectPoint, ethernetPkt.getDestinationMAC());
Saurav Das987441a2018-09-18 16:33:47 -0700678 }
Ray Milkey967776a2015-10-07 14:37:17 -0700679 packetService.emit(packet);
Shubham Sharma1f193582019-07-11 12:12:41 +0000680 if (isChallengeResponse) {
681 aaaStatisticsManager.getAaaStats().incrementEapPktTxauthEap();
682 }
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000683 aaaStatisticsManager.getAaaStats().incrementEapolFramesTx();
684 aaaStatisticsManager.getAaaStats().countReqEapFramesTx();
Ray Milkey967776a2015-10-07 14:37:17 -0700685 }
686
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400687 @Override
688 public String toString() {
689 return ToStringBuilder.reflectionToString(this);
690 }
691
Jonathan Hart612651f2019-11-25 09:21:43 -0800692 @Override
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800693 public Iterable<AuthenticationRecord> getAuthenticationRecords() {
Hardik Windlassd0b49692020-02-26 18:17:14 +0000694 return authentications.values();
Jonathan Hart612651f2019-11-25 09:21:43 -0800695 }
696
697 @Override
698 public boolean removeAuthenticationStateByMac(MacAddress mac) {
699
Hardik Windlassd0b49692020-02-26 18:17:14 +0000700 Optional<AuthenticationRecord> r = authentications.values().stream()
701 .filter(v -> v.supplicantAddress().equals(mac))
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800702 .findFirst();
Jonathan Hart612651f2019-11-25 09:21:43 -0800703
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800704 if (r.isEmpty()) {
705 return false;
Jonathan Hart612651f2019-11-25 09:21:43 -0800706 }
707
Hardik Windlassd0b49692020-02-26 18:17:14 +0000708 AuthenticationRecord removed =
709 authentications.remove(r.get().supplicantConnectPoint());
Jonathan Hart612651f2019-11-25 09:21:43 -0800710
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800711 return removed != null;
Jonathan Hart612651f2019-11-25 09:21:43 -0800712 }
713
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800714 StateMachine getStateMachine(String sessionId) {
Jonathan Hart612651f2019-11-25 09:21:43 -0800715 return stateMachines.get(sessionId);
716 }
717
718 private String sessionId(ConnectPoint cp) {
719 return cp.deviceId().toString() + cp.port().toString();
720 }
721
Ari Saha89831742015-06-26 10:31:48 -0700722 // our handler defined as a private inner class
723
724 /**
725 * Packet processor responsible for forwarding packets along their paths.
726 */
727 private class ReactivePacketProcessor implements PacketProcessor {
728 @Override
729 public void process(PacketContext context) {
Andrea Campanellac4781e62020-10-08 12:58:45 +0200730 packetProcessorExecutor.execute(() -> {
731 // Extract the original Ethernet frame from the packet information
732 InboundPacket pkt = context.inPacket();
733 Ethernet ethPkt = pkt.parsed();
734 if (ethPkt == null) {
735 return;
736 }
Ari Saha89831742015-06-26 10:31:48 -0700737
Andrea Campanellac4781e62020-10-08 12:58:45 +0200738 // identify if incoming packet comes from supplicant (EAP) or RADIUS
739 switch (EthType.EtherType.lookup(ethPkt.getEtherType())) {
740 case EAPOL:
741 handleSupplicantPacket(context.inPacket());
742 break;
743 default:
744 // any other packets let the specific implementation handle
745 impl.handlePacketFromServer(context);
746 }
747 });
Ari Saha89831742015-06-26 10:31:48 -0700748 }
749
Ray Milkey9eb293f2015-09-30 15:09:17 -0700750 /**
751 * Creates and initializes common fields of a RADIUS packet.
752 *
Ray Milkey967776a2015-10-07 14:37:17 -0700753 * @param stateMachine state machine for the request
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700754 * @param eapPacket EAP packet
Ray Milkey9eb293f2015-09-30 15:09:17 -0700755 * @return RADIUS packet
756 */
Ray Milkey967776a2015-10-07 14:37:17 -0700757 private RADIUS getRadiusPayload(StateMachine stateMachine, byte identifier, EAP eapPacket) {
Ray Milkey9eb293f2015-09-30 15:09:17 -0700758 RADIUS radiusPayload =
759 new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
760 eapPacket.getIdentifier());
Ray Milkey967776a2015-10-07 14:37:17 -0700761
762 // set Request Authenticator in StateMachine
763 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
764
Ray Milkey9eb293f2015-09-30 15:09:17 -0700765 radiusPayload.setIdentifier(identifier);
766 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
Ray Milkey967776a2015-10-07 14:37:17 -0700767 stateMachine.username());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700768
769 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
Jonathan Hart092dfb22015-11-16 23:05:21 -0800770 AaaManager.this.nasIpAddress.getAddress());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700771
772 radiusPayload.encapsulateMessage(eapPacket);
Ray Milkey9eb293f2015-09-30 15:09:17 -0700773
774 return radiusPayload;
775 }
Ari Saha89831742015-06-26 10:31:48 -0700776
777 /**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700778 * Handles PAE packets (supplicant).
779 *
780 * @param inPacket Ethernet packet coming from the supplicant
Ari Saha89831742015-06-26 10:31:48 -0700781 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800782 private void handleSupplicantPacket(InboundPacket inPacket) {
Jonathan Harta46dddf2015-06-30 15:31:20 -0700783 Ethernet ethPkt = inPacket.parsed();
Ari Saha89831742015-06-26 10:31:48 -0700784 // Where does it come from?
Jonathan Hart092dfb22015-11-16 23:05:21 -0800785 MacAddress srcMac = ethPkt.getSourceMAC();
Ari Saha89831742015-06-26 10:31:48 -0700786
Jonathan Harta46dddf2015-06-30 15:31:20 -0700787 DeviceId deviceId = inPacket.receivedFrom().deviceId();
788 PortNumber portNumber = inPacket.receivedFrom().port();
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800789 String sessionId = sessionId(inPacket.receivedFrom());
Saurav Das987441a2018-09-18 16:33:47 -0700790 EAPOL eapol = (EAPOL) ethPkt.getPayload();
791 if (log.isTraceEnabled()) {
792 log.trace("Received EAPOL packet {} in enclosing packet {} from "
Andrea Campanellac4781e62020-10-08 12:58:45 +0200793 + "dev/port: {}/{} with MacAddress {}",
794 eapol, ethPkt, deviceId,
795 portNumber, srcMac);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100796 }
Jonathan Harta46dddf2015-06-30 15:31:20 -0700797
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000798 short pktlen = eapol.getPacketLength();
799 byte[] eapPayLoadBuffer = eapol.serialize();
800 int len = eapPayLoadBuffer.length;
801 if (len != (HEADER_LENGTH + pktlen)) {
802 aaaStatisticsManager.getAaaStats().incrementInvalidBodyLength();
803 return;
804 }
805 if (!VALID_EAPOL_TYPE.contains(eapol.getEapolType())) {
806 aaaStatisticsManager.getAaaStats().incrementInvalidPktType();
807 return;
808 }
809 if (pktlen >= 0 && ethPkt.getEtherType() == EthType.EtherType.EAPOL.ethType().toShort()) {
810 aaaStatisticsManager.getAaaStats().incrementValidEapolFramesRx();
811 }
Jonathan Hart612651f2019-11-25 09:21:43 -0800812
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700813 StateMachine stateMachine = stateMachines.computeIfAbsent(sessionId, id ->
814 new StateMachine(id, serverStatusAndStateMachineTimeoutExecutor));
Jonathan Hart612651f2019-11-25 09:21:43 -0800815 stateMachine.setEapolTypeVal(eapol.getEapolType());
Saurav Das987441a2018-09-18 16:33:47 -0700816
Ari Saha89831742015-06-26 10:31:48 -0700817 switch (eapol.getEapolType()) {
818 case EAPOL.EAPOL_START:
Andrea Campanellac4781e62020-10-08 12:58:45 +0200819 log.debug("EAP packet: EAPOL_START from dev/port: {}/{} with MacAddress {}",
820 deviceId, portNumber, srcMac);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700821 stateMachine.setSupplicantConnectpoint(inPacket.receivedFrom());
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800822 stateMachine.setSupplicantAddress(srcMac);
Jonathan Hart5db44532018-07-12 18:13:54 -0700823 stateMachine.start();
Jonathan Hart612651f2019-11-25 09:21:43 -0800824
Andrea Campanella76ae68d2020-10-14 11:16:37 +0200825 aaaStatisticsManager.getAaaStats().incrementEapolStartReqRx();
Ray Milkeyf51eba22015-09-25 10:24:23 -0700826 //send an EAP Request/Identify to the supplicant
827 EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.identifier(), EAP.ATTR_IDENTITY, null);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100828 if (ethPkt.getVlanID() != Ethernet.VLAN_UNTAGGED) {
829 stateMachine.setPriorityCode(ethPkt.getPriorityCode());
830 }
Jonathan Hart092dfb22015-11-16 23:05:21 -0800831 Ethernet eth = buildEapolResponse(srcMac, MacAddress.valueOf(nasMacAddress),
Ray Milkeyf51eba22015-09-25 10:24:23 -0700832 ethPkt.getVlanID(), EAPOL.EAPOL_PACKET,
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100833 eapPayload, stateMachine.priorityCode());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400834
Ray Milkeyf51eba22015-09-25 10:24:23 -0700835 stateMachine.setVlanId(ethPkt.getVlanID());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400836 log.debug("Getting EAP identity from supplicant {}", stateMachine.supplicantAddress().toString());
Shubham Sharma1f193582019-07-11 12:12:41 +0000837 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint(), false);
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000838 aaaStatisticsManager.getAaaStats().incrementRequestIdFramesTx();
Ari Saha89831742015-06-26 10:31:48 -0700839
840 break;
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800841 case EAPOL.EAPOL_LOGOFF:
Andrea Campanellac4781e62020-10-08 12:58:45 +0200842 log.debug("EAP packet: EAPOL_LOGOFF from dev/port: {}/{} with MacAddress {}",
843 deviceId, portNumber, srcMac);
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +0000844 //posting the machine stat data for current supplicant device.
845 if (stateMachine.getSessionTerminateReason() == null ||
846 stateMachine.getSessionTerminateReason().equals("")) {
847 stateMachine.setSessionTerminateReason(
848 StateMachine.SessionTerminationReasons.SUPPLICANT_LOGOFF.getReason());
849 }
850 AaaSupplicantMachineStats obj = aaaSupplicantStatsManager.getSupplicantStats(stateMachine);
851 aaaSupplicantStatsManager.getMachineStatsDelegate()
852 .notify(new AaaMachineStatisticsEvent(AaaMachineStatisticsEvent.Type.STATS_UPDATE, obj));
Ray Milkeyb34b4962016-01-04 10:24:43 -0800853 if (stateMachine.state() == StateMachine.STATE_AUTHORIZED) {
854 stateMachine.logoff();
Shubham Sharma1f193582019-07-11 12:12:41 +0000855 aaaStatisticsManager.getAaaStats().incrementEapolLogoffRx();
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800856 }
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000857 if (stateMachine.state() == StateMachine.STATE_IDLE) {
858 aaaStatisticsManager.getAaaStats().incrementAuthStateIdle();
859 }
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800860
861 break;
Ari Saha89831742015-06-26 10:31:48 -0700862 case EAPOL.EAPOL_PACKET:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700863 RADIUS radiusPayload;
Ray Milkey9eb293f2015-09-30 15:09:17 -0700864 // check if this is a Response/Identify or a Response/TLS
Ari Saha89831742015-06-26 10:31:48 -0700865 EAP eapPacket = (EAP) eapol.getPayload();
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000866 Byte identifier = new Byte(eapPacket.getIdentifier());
Ari Saha89831742015-06-26 10:31:48 -0700867
Jonathan Hart612651f2019-11-25 09:21:43 -0800868 // get identifier for request and store mapping to session ID
869 RequestIdentifier radiusIdentifier = idManager.getNewIdentifier(sessionId);
870
Ari Saha89831742015-06-26 10:31:48 -0700871 byte dataType = eapPacket.getDataType();
872 switch (dataType) {
Ari Saha89831742015-06-26 10:31:48 -0700873
Ray Milkey9eb293f2015-09-30 15:09:17 -0700874 case EAP.ATTR_IDENTITY:
Andrea Campanellac4781e62020-10-08 12:58:45 +0200875 log.debug("EAP packet: EAPOL_PACKET ATTR_IDENTITY from dev/port: {}/{} with MacAddress {}",
876 deviceId, portNumber, srcMac);
Shubham Sharma1e43c562019-06-19 14:18:12 +0000877 //Setting the time of this response from RG, only when its not a re-transmission.
878 if (stateMachine.getLastPacketReceivedTime() == 0) {
879 stateMachine.setLastPacketReceivedTime(System.currentTimeMillis());
880 }
Ray Milkey9eb293f2015-09-30 15:09:17 -0700881 // request id access to RADIUS
882 stateMachine.setUsername(eapPacket.getData());
Ari Saha89831742015-06-26 10:31:48 -0700883
Jonathan Hart612651f2019-11-25 09:21:43 -0800884 radiusPayload = getRadiusPayload(stateMachine, radiusIdentifier.identifier(), eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100885 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Andrea Campanellac4781e62020-10-08 12:58:45 +0200886 radiusPayload.addMessageAuthenticator(radiusSecret);
887
888 if (log.isTraceEnabled()) {
889 log.trace("Sending ATTR_IDENTITY packet to RADIUS for supplicant at dev/port: " +
890 "{}/{} with MacAddress {}", deviceId, portNumber, srcMac);
891 }
Ari Saha89831742015-06-26 10:31:48 -0700892
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100893 sendRadiusPacket(radiusPayload, inPacket);
Shubham Sharma1e43c562019-06-19 14:18:12 +0000894 stateMachine.setWaitingForRadiusResponse(true);
Andrea Campanella76ae68d2020-10-14 11:16:37 +0200895 aaaStatisticsManager.getAaaStats().incrementRadiusReqIdTx();
Shubham Sharma1f193582019-07-11 12:12:41 +0000896 aaaStatisticsManager.getAaaStats().incrementEapolAtrrIdentity();
Ray Milkey9eb293f2015-09-30 15:09:17 -0700897 // change the state to "PENDING"
kartikey dubeye1545422019-05-22 12:53:45 +0000898 if (stateMachine.state() == StateMachine.STATE_PENDING) {
899 aaaStatisticsManager.getAaaStats().increaseRequestReTx();
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +0000900 stateMachine.incrementTotalPacketsSent();
901 stateMachine.incrementTotalOctetSent(eapol.getPacketLength());
kartikey dubeye1545422019-05-22 12:53:45 +0000902 }
Ray Milkey9eb293f2015-09-30 15:09:17 -0700903 stateMachine.requestAccess();
904 break;
Ari Saha89831742015-06-26 10:31:48 -0700905 case EAP.ATTR_MD5:
Andrea Campanellac4781e62020-10-08 12:58:45 +0200906 log.debug("EAP packet: EAPOL_PACKET ATTR_MD5 from dev/port: {}/{} with MacAddress {}",
907 deviceId, portNumber, srcMac);
Ray Milkey9eb293f2015-09-30 15:09:17 -0700908 // verify if the EAP identifier corresponds to the
909 // challenge identifier from the client state
910 // machine.
Andrea Campanella76ae68d2020-10-14 11:16:37 +0200911 stateMachine.setLastPacketReceivedTime(System.currentTimeMillis());
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700912 if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) {
Ari Saha89831742015-06-26 10:31:48 -0700913 //send the RADIUS challenge response
Jonathan Hart612651f2019-11-25 09:21:43 -0800914 radiusPayload = getRadiusPayload(stateMachine,
915 radiusIdentifier.identifier(), eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100916 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700917
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800918 if (stateMachine.challengeState() != null) {
919 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
920 stateMachine.challengeState());
921 }
Andrea Campanellac4781e62020-10-08 12:58:45 +0200922 radiusPayload.addMessageAuthenticator(radiusSecret);
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000923 if (outPacketSupp.contains(eapPacket.getIdentifier())) {
Andrea Campanella76ae68d2020-10-14 11:16:37 +0200924 aaaStatisticsManager.getAaaStats().decrementPendingReqSupp();
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000925 outPacketSupp.remove(identifier);
926 }
Andrea Campanellac4781e62020-10-08 12:58:45 +0200927 if (log.isTraceEnabled()) {
928 log.trace("Sending ATTR_MD5 packet to RADIUS for supplicant at dev/port: " +
929 "{}/{} with MacAddress {}", deviceId, portNumber, srcMac);
930 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100931 sendRadiusPacket(radiusPayload, inPacket);
Shubham Sharma1e43c562019-06-19 14:18:12 +0000932 stateMachine.setWaitingForRadiusResponse(true);
Andrea Campanella76ae68d2020-10-14 11:16:37 +0200933 aaaStatisticsManager.getAaaStats().incrementRadiusReqChallengeTx();
Shubham Sharma1f193582019-07-11 12:12:41 +0000934 aaaStatisticsManager.getAaaStats().incrementEapolMd5RspChall();
Ari Saha89831742015-06-26 10:31:48 -0700935 }
936 break;
937 case EAP.ATTR_TLS:
Andrea Campanellac4781e62020-10-08 12:58:45 +0200938 log.debug("EAP packet: EAPOL_PACKET ATTR_TLS from dev/port: {}/{} with MacAddress {}",
939 deviceId, portNumber, srcMac);
Ray Milkey9eb293f2015-09-30 15:09:17 -0700940 // request id access to RADIUS
Jonathan Hart612651f2019-11-25 09:21:43 -0800941 radiusPayload = getRadiusPayload(stateMachine, radiusIdentifier.identifier(), eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100942 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700943
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800944 if (stateMachine.challengeState() != null) {
945 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
946 stateMachine.challengeState());
947 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700948 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
Andrea Campanellac4781e62020-10-08 12:58:45 +0200949 radiusPayload.addMessageAuthenticator(radiusSecret);
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000950 if (outPacketSupp.contains(eapPacket.getIdentifier())) {
Andrea Campanella76ae68d2020-10-14 11:16:37 +0200951 aaaStatisticsManager.getAaaStats().decrementPendingReqSupp();
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000952 outPacketSupp.remove(identifier);
953 }
Andrea Campanellac4781e62020-10-08 12:58:45 +0200954 if (log.isTraceEnabled()) {
955 log.trace("Sending ATTR_TLS packet to RADIUS for supplicant at dev/port: " +
956 "{}/{} with MacAddress {}", deviceId, portNumber, srcMac);
957 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100958 sendRadiusPacket(radiusPayload, inPacket);
Shubham Sharma1e43c562019-06-19 14:18:12 +0000959 stateMachine.setWaitingForRadiusResponse(true);
Andrea Campanella76ae68d2020-10-14 11:16:37 +0200960 aaaStatisticsManager.getAaaStats().incrementRadiusReqChallengeTx();
Shubham Sharma1f193582019-07-11 12:12:41 +0000961 aaaStatisticsManager.getAaaStats().incrementEapolTlsRespChall();
Ray Milkey5493b512015-10-21 12:13:49 -0700962
Ray Milkeyf3790b82015-10-21 16:28:08 -0700963 if (stateMachine.state() != StateMachine.STATE_PENDING) {
964 stateMachine.requestAccess();
965 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700966
Ari Saha89831742015-06-26 10:31:48 -0700967 break;
968 default:
Andrea Campanellac4781e62020-10-08 12:58:45 +0200969 log.warn("Unknown EAP packet type from dev/port: {}/{} with MacAddress {}",
970 deviceId, portNumber, srcMac);
Ari Saha89831742015-06-26 10:31:48 -0700971 return;
972 }
973 break;
974 default:
Andrea Campanellac4781e62020-10-08 12:58:45 +0200975 log.debug("Skipping EAPOL message {} from dev/port: {}/{} with MacAddress {}",
976 eapol.getEapolType(), deviceId, portNumber, srcMac);
Ari Saha89831742015-06-26 10:31:48 -0700977 }
Shubham Sharma1f193582019-07-11 12:12:41 +0000978 aaaStatisticsManager.getAaaStats().countTransRespNotNak();
979 aaaStatisticsManager.getAaaStats().countEapolResIdentityMsgTrans();
Ari Saha89831742015-06-26 10:31:48 -0700980 }
Ray Milkey967776a2015-10-07 14:37:17 -0700981 }
982
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100983 /**
Jonathan Hart5db44532018-07-12 18:13:54 -0700984 * Delegate allowing the StateMachine to notify us of events.
985 */
986 private class InternalStateMachineDelegate implements StateMachineDelegate {
987
988 @Override
989 public void notify(AuthenticationEvent authenticationEvent) {
990 log.info("Auth event {} for {}",
991 authenticationEvent.type(), authenticationEvent.subject());
Jonathan Hart612651f2019-11-25 09:21:43 -0800992
993 if (authenticationEvent.type() == AuthenticationEvent.Type.TIMEOUT) {
994 handleStateMachineTimeout(authenticationEvent.subject());
995 }
996
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800997 AuthenticationRecord record = authenticationEvent.authenticationRecord();
998 if (record == null) {
999 authentications.remove(authenticationEvent.subject());
1000 } else {
1001 authentications.put(authenticationEvent.subject(), record);
1002 }
1003
Jonathan Hart5db44532018-07-12 18:13:54 -07001004 post(authenticationEvent);
1005 }
1006 }
1007
Jonathan Hart612651f2019-11-25 09:21:43 -08001008 private void handleStateMachineTimeout(ConnectPoint supplicantConnectPoint) {
1009 StateMachine stateMachine = stateMachines.remove(sessionId(supplicantConnectPoint));
Andrea Campanellae66466a2020-02-03 14:05:45 +00001010 //pushing captured machine stats to kafka
1011 stateMachine.setSessionTerminateReason("Time out");
1012 AaaSupplicantMachineStats obj = aaaSupplicantStatsManager
1013 .getSupplicantStats(stateMachine);
1014 aaaSupplicantStatsManager.getMachineStatsDelegate()
1015 .notify(new AaaMachineStatisticsEvent(
1016 AaaMachineStatisticsEvent.Type.STATS_UPDATE, obj));
1017
Jonathan Hart612651f2019-11-25 09:21:43 -08001018 if (stateMachine.state() == StateMachine.STATE_PENDING && stateMachine.isWaitingForRadiusResponse()) {
1019 aaaStatisticsManager.getAaaStats().increaseTimedOutPackets();
1020 }
1021
1022 StateMachine.deleteStateMachineMapping(stateMachine);
1023 }
1024
Jonathan Hart5db44532018-07-12 18:13:54 -07001025 /**
Amit Ghoshc9ac1e52017-07-28 12:31:18 +01001026 * Configuration Listener, handles change in configuration.
1027 */
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001028 private class InternalConfigListener implements NetworkConfigListener {
1029
1030 /**
Ray Milkeyc9e8dcc2015-12-30 10:31:32 -08001031 * Reconfigures the AAA application according to the
1032 * configuration parameters passed.
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001033 *
1034 * @param cfg configuration object
1035 */
Jonathan Hart092dfb22015-11-16 23:05:21 -08001036 private void reconfigureNetwork(AaaConfig cfg) {
Matt Jeanneret2ff1a782018-06-13 15:24:25 -04001037 log.info("Reconfiguring AaaConfig from config: {}", cfg);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +01001038
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001039 if (cfg == null) {
Jonathan Hart092dfb22015-11-16 23:05:21 -08001040 newCfg = new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001041 } else {
1042 newCfg = cfg;
1043 }
1044 if (newCfg.nasIp() != null) {
1045 nasIpAddress = newCfg.nasIp();
1046 }
1047 if (newCfg.radiusIp() != null) {
1048 radiusIpAddress = newCfg.radiusIp();
1049 }
1050 if (newCfg.radiusMac() != null) {
1051 radiusMacAddress = newCfg.radiusMac();
1052 }
1053 if (newCfg.nasMac() != null) {
1054 nasMacAddress = newCfg.nasMac();
1055 }
Andrea Campanellac4781e62020-10-08 12:58:45 +02001056 if (newCfg.radiusSecret() != null && !newCfg.radiusSecret().equals(radiusSecret)) {
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001057 radiusSecret = newCfg.radiusSecret();
Andrea Campanellac4781e62020-10-08 12:58:45 +02001058 radiusOperationalStatusService.initialize(nasIpAddress.getAddress(), radiusSecret, impl);
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001059 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +01001060
Deepa Vaddireddye0e10722017-09-27 05:00:10 +05301061 boolean reconfigureCustomizer = false;
1062 if (customizer == null || !customizer.equals(newCfg.radiusPktCustomizer())) {
1063 customizer = newCfg.radiusPktCustomizer();
1064 configurePacketCustomizer();
1065 reconfigureCustomizer = true;
1066 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +01001067
Deepa Vaddireddye0e10722017-09-27 05:00:10 +05301068 if (radiusConnectionType == null
1069 || reconfigureCustomizer
1070 || !radiusConnectionType.equals(newCfg.radiusConnectionType())) {
1071 radiusConnectionType = newCfg.radiusConnectionType();
1072 if (impl != null) {
1073 impl.withdrawIntercepts();
1074 impl.clearLocalState();
1075 }
1076 configureRadiusCommunication();
1077 impl.initializeLocalState(newCfg);
1078 impl.requestIntercepts();
1079 } else if (impl != null) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +01001080 impl.clearLocalState();
1081 impl.initializeLocalState(newCfg);
Ray Milkey5d99bd12015-10-06 15:41:30 -07001082 }
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001083 }
1084
1085 @Override
1086 public void event(NetworkConfigEvent event) {
1087
1088 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
1089 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
Jonathan Hart092dfb22015-11-16 23:05:21 -08001090 event.configClass().equals(AaaConfig.class)) {
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001091
Jonathan Hart092dfb22015-11-16 23:05:21 -08001092 AaaConfig cfg = netCfgService.getConfig(appId, AaaConfig.class);
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001093 reconfigureNetwork(cfg);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +01001094
Matt Jeanneret2ff1a782018-06-13 15:24:25 -04001095 log.info("Reconfigured: {}", cfg.toString());
Ray Milkeyfcb623d2015-10-01 16:48:18 -07001096 }
1097 }
1098 }
Amit Ghoshf739be52017-09-21 15:49:37 +01001099
Jonathan Hart9d1ce802020-01-28 10:45:08 -08001100 private class InternalMapEventListener implements MapEventListener<ConnectPoint, AuthenticationRecord> {
1101 @Override
1102 public void event(MapEvent<ConnectPoint, AuthenticationRecord> event) {
1103 if (event.type() == MapEvent.Type.REMOVE) {
1104 // remove local state machine if user has requested remove
1105 StateMachine sm = stateMachines.remove(sessionId(event.key()));
1106 if (sm != null) {
1107 sm.stop();
1108 }
1109 }
1110 }
1111 }
1112
Amit Ghoshf739be52017-09-21 15:49:37 +01001113 private class InternalDeviceListener implements DeviceListener {
1114 @Override
1115 public void event(DeviceEvent event) {
Andrea Campanellabba33672020-02-11 14:03:01 +01001116 DeviceId deviceId = event.subject().id();
Amit Ghoshf739be52017-09-21 15:49:37 +01001117 switch (event.type()) {
1118 case PORT_REMOVED:
Amit Ghoshf739be52017-09-21 15:49:37 +01001119 PortNumber portNumber = event.port().number();
Andrea Campanellabba33672020-02-11 14:03:01 +01001120 String sessionId = deviceId.toString() + portNumber.toString();
Girish Kumar064084c2020-02-04 08:32:46 +00001121 log.debug("Received PORT_REMOVED event. Clearing AAA Session with Id {}", sessionId);
Hardik Windlass75c67712020-02-21 10:57:20 +00001122
Girish Kumar064084c2020-02-04 08:32:46 +00001123 flushStateMachineSession(sessionId,
1124 StateMachine.SessionTerminationReasons.PORT_REMOVED.getReason());
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +00001125
Girish Kumar064084c2020-02-04 08:32:46 +00001126 break;
Girish Kumar064084c2020-02-04 08:32:46 +00001127 case DEVICE_REMOVED:
Girish Kumar064084c2020-02-04 08:32:46 +00001128 log.debug("Received DEVICE_REMOVED event for {}", deviceId);
Andrea Campanellabba33672020-02-11 14:03:01 +01001129 clearAllSessionStateForDevice(deviceId);
Amit Ghoshf739be52017-09-21 15:49:37 +01001130 break;
Girish Kumar064084c2020-02-04 08:32:46 +00001131
Amit Ghoshf739be52017-09-21 15:49:37 +01001132 default:
1133 return;
1134 }
1135 }
Girish Kumar064084c2020-02-04 08:32:46 +00001136
Andrea Campanellabba33672020-02-11 14:03:01 +01001137 private void clearAllSessionStateForDevice(DeviceId deviceId) {
1138 Set<String> associatedSessions = Sets.newHashSet();
1139 for (Entry<String, StateMachine> stateMachineEntry : stateMachines.entrySet()) {
1140 ConnectPoint cp = stateMachineEntry.getValue().supplicantConnectpoint();
1141 if (cp != null && cp.deviceId().toString().equals(deviceId.toString())) {
1142 associatedSessions.add(stateMachineEntry.getKey());
1143 }
1144 }
1145
1146 for (String session : associatedSessions) {
1147 log.debug("Clearing AAA Session {} associated with Removed Device", session);
1148 flushStateMachineSession(session,
1149 StateMachine.SessionTerminationReasons.DEVICE_REMOVED.getReason());
1150 }
1151 }
1152
Girish Kumar064084c2020-02-04 08:32:46 +00001153 private void flushStateMachineSession(String sessionId, String terminationReason) {
1154 StateMachine stateMachine = stateMachines.get(sessionId);
Girish Kumare5a1aa92020-02-14 14:08:54 +00001155 if (stateMachine == null) {
1156 // No active AAA sessions for this UNI port
1157 log.debug("No Active AAA Session found with Id {}", sessionId);
1158 return;
Girish Kumar064084c2020-02-04 08:32:46 +00001159 }
1160
Hardik Windlass9a09b832020-02-25 11:45:35 +00001161 authentications.remove(stateMachine.supplicantConnectpoint());
Girish Kumare5a1aa92020-02-14 14:08:54 +00001162 stateMachine.setSessionTerminateReason(terminationReason);
1163
Girish Kumar064084c2020-02-04 08:32:46 +00001164 //pushing captured machine stats to kafka
1165 AaaSupplicantMachineStats obj = aaaSupplicantStatsManager.getSupplicantStats(stateMachine);
1166 aaaSupplicantStatsManager.getMachineStatsDelegate()
1167 .notify(new AaaMachineStatisticsEvent(AaaMachineStatisticsEvent.Type.STATS_UPDATE, obj));
Girish Kumar064084c2020-02-04 08:32:46 +00001168 StateMachine removed = stateMachines.remove(sessionId);
Shubham Sharma8d7a9822020-01-28 10:04:01 +00001169
Girish Kumar064084c2020-02-04 08:32:46 +00001170 if (removed != null) {
1171 StateMachine.deleteStateMachineMapping(removed);
1172 }
1173 }
Amit Ghoshf739be52017-09-21 15:49:37 +01001174 }
Girish Kumar064084c2020-02-04 08:32:46 +00001175
Shubham Sharma4900ce62019-06-19 14:18:50 +00001176 private class ServerStatusChecker implements Runnable {
1177 @Override
1178 public void run() {
Matteo Scandolo3498bc02020-01-08 09:54:12 -08001179 log.debug("Notifying RadiusOperationalStatusEvent");
Shubham Sharma4900ce62019-06-19 14:18:50 +00001180 radiusOperationalStatusService.checkServerOperationalStatus();
Matteo Scandolo3498bc02020-01-08 09:54:12 -08001181 log.trace("--POSTING--" + radiusOperationalStatusService.getRadiusServerOperationalStatus());
Shubham Sharma4900ce62019-06-19 14:18:50 +00001182 radiusOperationalStatusService.getRadiusOprStDelegate()
1183 .notify(new RadiusOperationalStatusEvent(
1184 RadiusOperationalStatusEvent.Type.RADIUS_OPERATIONAL_STATUS,
1185 radiusOperationalStatusService.
1186 getRadiusServerOperationalStatus()));
kartikey dubeye1545422019-05-22 12:53:45 +00001187 }
Shubham Sharma4900ce62019-06-19 14:18:50 +00001188
1189 }
Shubham Sharma544ffa22020-02-13 06:41:02 +00001190
1191 @Override
1192 public AaaSupplicantMachineStats getSupplicantMachineStats(String sessionId) {
1193 StateMachine aaaSupplicantMachine = stateMachines.get(sessionId);
1194 if (aaaSupplicantMachine != null) {
1195 return aaaSupplicantStatsManager.getSupplicantStats(aaaSupplicantMachine);
1196 } else {
1197 return null;
1198 }
1199 }
Jonathan Hart612651f2019-11-25 09:21:43 -08001200}