blob: 55b6726581d88a023c2fe4083975887d96e55f07 [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
Saurav Das987441a2018-09-18 16:33:47 -070018import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
19import static org.slf4j.LoggerFactory.getLogger;
20
21import java.net.InetAddress;
kartikey dubeye1545422019-05-22 12:53:45 +000022import java.net.UnknownHostException;
Saurav Das987441a2018-09-18 16:33:47 -070023import java.nio.ByteBuffer;
24import java.util.Map;
kartikey dubeye1545422019-05-22 12:53:45 +000025import java.util.Dictionary;
26import java.util.HashSet;
Vijaykumar Kushwaha056e4cd2019-08-06 13:16:25 +000027import java.util.Arrays;
Shubham Sharma3c8c7022019-09-13 10:39:47 +000028import java.util.List;
Saurav Das987441a2018-09-18 16:33:47 -070029
Jonathan Hart932bedc2018-07-12 13:46:09 -070030import org.apache.commons.lang3.builder.ToStringBuilder;
Carmelo Cascone58b53292019-09-30 12:35:31 -070031import org.osgi.service.component.annotations.Component;
32import org.osgi.service.component.annotations.Deactivate;
33import org.osgi.service.component.annotations.Reference;
34import org.osgi.service.component.annotations.ReferenceCardinality;
Jonathan Hart4731dd92018-05-02 17:30:05 -070035import org.onlab.packet.DeserializationException;
Jonathan Harta46dddf2015-06-30 15:31:20 -070036import org.onlab.packet.EAP;
37import org.onlab.packet.EAPOL;
38import org.onlab.packet.EthType;
Ari Saha89831742015-06-26 10:31:48 -070039import org.onlab.packet.Ethernet;
Ari Saha89831742015-06-26 10:31:48 -070040import org.onlab.packet.MacAddress;
Jonathan Harta46dddf2015-06-30 15:31:20 -070041import org.onlab.packet.RADIUS;
42import org.onlab.packet.RADIUSAttribute;
kartikey dubeye1545422019-05-22 12:53:45 +000043import org.onlab.util.Tools;
44import org.onosproject.cfg.ComponentConfigService;
Ari Saha89831742015-06-26 10:31:48 -070045import org.onosproject.core.ApplicationId;
46import org.onosproject.core.CoreService;
Jonathan Hart5db44532018-07-12 18:13:54 -070047import org.onosproject.event.AbstractListenerManager;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010048import org.onosproject.mastership.MastershipService;
Ari Saha89831742015-06-26 10:31:48 -070049import org.onosproject.net.ConnectPoint;
50import org.onosproject.net.DeviceId;
Ari Saha89831742015-06-26 10:31:48 -070051import org.onosproject.net.PortNumber;
Ray Milkeyfcb623d2015-10-01 16:48:18 -070052import org.onosproject.net.config.ConfigFactory;
53import org.onosproject.net.config.NetworkConfigEvent;
54import org.onosproject.net.config.NetworkConfigListener;
55import org.onosproject.net.config.NetworkConfigRegistry;
Amit Ghoshf739be52017-09-21 15:49:37 +010056import org.onosproject.net.device.DeviceEvent;
57import org.onosproject.net.device.DeviceListener;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010058import org.onosproject.net.device.DeviceService;
Ari Saha89831742015-06-26 10:31:48 -070059import org.onosproject.net.flow.DefaultTrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070060import org.onosproject.net.flow.TrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070061import org.onosproject.net.packet.DefaultOutboundPacket;
62import org.onosproject.net.packet.InboundPacket;
63import org.onosproject.net.packet.OutboundPacket;
64import org.onosproject.net.packet.PacketContext;
Ari Saha89831742015-06-26 10:31:48 -070065import org.onosproject.net.packet.PacketProcessor;
66import org.onosproject.net.packet.PacketService;
Matteo Scandolocf847b82019-04-26 15:00:00 -070067import org.opencord.aaa.AaaConfig;
68import org.opencord.aaa.AuthenticationEvent;
69import org.opencord.aaa.AuthenticationEventListener;
70import org.opencord.aaa.AuthenticationService;
kartikey dubeye1545422019-05-22 12:53:45 +000071import org.opencord.aaa.AuthenticationStatisticsEvent;
72import org.opencord.aaa.AuthenticationStatisticsService;
Matteo Scandolocf847b82019-04-26 15:00:00 -070073import org.opencord.aaa.RadiusCommunicator;
74import org.opencord.aaa.StateMachineDelegate;
Gamze Abaka1cfdb192018-10-25 11:39:19 +000075import org.opencord.sadis.BaseInformationService;
76import org.opencord.sadis.SadisService;
77import org.opencord.sadis.SubscriberAndDeviceInformation;
kartikey dubeye1545422019-05-22 12:53:45 +000078import org.osgi.service.component.ComponentContext;
Carmelo Cascone58b53292019-09-30 12:35:31 -070079import org.osgi.service.component.annotations.Modified;
80import org.osgi.service.component.annotations.Activate;
Ari Saha89831742015-06-26 10:31:48 -070081import org.slf4j.Logger;
kartikey dubeye1545422019-05-22 12:53:45 +000082import com.google.common.base.Strings;
Ari Saha89831742015-06-26 10:31:48 -070083
kartikey dubeye1545422019-05-22 12:53:45 +000084import java.util.concurrent.Executors;
85import java.util.concurrent.ScheduledExecutorService;
86import java.util.concurrent.ScheduledFuture;
87import java.util.concurrent.TimeUnit;
Vijaykumar Kushwaha056e4cd2019-08-06 13:16:25 +000088
Carmelo Cascone58b53292019-09-30 12:35:31 -070089import static org.opencord.aaa.impl.OsgiPropertyConstants.STATISTICS_GENERATION_EVENT;
90import static org.opencord.aaa.impl.OsgiPropertyConstants.STATISTICS_GENERATION_EVENT_DEFAULT;
91
Vijaykumar Kushwaha056e4cd2019-08-06 13:16:25 +000092import javax.crypto.Mac;
93import javax.crypto.spec.SecretKeySpec;
Ari Saha89831742015-06-26 10:31:48 -070094/**
Jonathan Harta46dddf2015-06-30 15:31:20 -070095 * AAA application for ONOS.
Ari Saha89831742015-06-26 10:31:48 -070096 */
Carmelo Cascone58b53292019-09-30 12:35:31 -070097@Component(immediate = true, property = {
98 STATISTICS_GENERATION_EVENT + ":Integer=" + STATISTICS_GENERATION_EVENT_DEFAULT,
99})
Jonathan Hart5db44532018-07-12 18:13:54 -0700100public class AaaManager
101 extends AbstractListenerManager<AuthenticationEvent, AuthenticationEventListener>
102 implements AuthenticationService {
103
Charles Chandf7ff862017-01-20 11:22:05 -0800104 private static final String APP_NAME = "org.opencord.aaa";
Ray Milkeyf51eba22015-09-25 10:24:23 -0700105
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700106 private final Logger log = getLogger(getClass());
Ray Milkeyf51eba22015-09-25 10:24:23 -0700107
Carmelo Cascone58b53292019-09-30 12:35:31 -0700108 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700109 protected CoreService coreService;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700110
Carmelo Cascone58b53292019-09-30 12:35:31 -0700111 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700112 protected PacketService packetService;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700113
Carmelo Cascone58b53292019-09-30 12:35:31 -0700114 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700115 protected NetworkConfigRegistry netCfgService;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700116
Carmelo Cascone58b53292019-09-30 12:35:31 -0700117 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100118 protected DeviceService deviceService;
119
Carmelo Cascone58b53292019-09-30 12:35:31 -0700120 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Gamze Abaka1cfdb192018-10-25 11:39:19 +0000121 protected SadisService sadisService;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100122
Carmelo Cascone58b53292019-09-30 12:35:31 -0700123 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100124 protected MastershipService mastershipService;
125
Carmelo Cascone58b53292019-09-30 12:35:31 -0700126 @Reference(cardinality = ReferenceCardinality.MANDATORY)
kartikey dubeye1545422019-05-22 12:53:45 +0000127 protected AuthenticationStatisticsService aaaStatisticsManager;
Gamze Abaka1cfdb192018-10-25 11:39:19 +0000128
Carmelo Cascone58b53292019-09-30 12:35:31 -0700129 @Reference(cardinality = ReferenceCardinality.MANDATORY)
kartikey dubeye1545422019-05-22 12:53:45 +0000130 protected ComponentConfigService cfgService;
131
132 protected AuthenticationStatisticsEventPublisher authenticationStatisticsPublisher;
133 protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
Amit Ghoshf739be52017-09-21 15:49:37 +0100134 private final DeviceListener deviceListener = new InternalDeviceListener();
135
Carmelo Cascone58b53292019-09-30 12:35:31 -0700136 /** Statistics generation interval. */
137 private int statisticsGenerationEvent = STATISTICS_GENERATION_EVENT_DEFAULT;
kartikey dubeye1545422019-05-22 12:53:45 +0000138
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700139 // NAS IP address
140 protected InetAddress nasIpAddress;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100141
142 // self MAC address
Jonathan Hart5db44532018-07-12 18:13:54 -0700143 protected String nasMacAddress;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100144
145 // Parsed RADIUS server addresses
146 protected InetAddress radiusIpAddress;
147
148 // MAC address of RADIUS server or net hop router
149 protected String radiusMacAddress;
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700150
151 // RADIUS server secret
152 protected String radiusSecret;
153
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100154 // bindings
155 protected CustomizationInfo customInfo;
Ray Milkey5d99bd12015-10-06 15:41:30 -0700156
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700157 // our application-specific event handler
158 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
Ray Milkeyf51eba22015-09-25 10:24:23 -0700159
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700160 // our unique identifier
161 private ApplicationId appId;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700162
Shubham Sharma1e43c562019-06-19 14:18:12 +0000163 // TimeOut time for cleaning up stateMachines stuck due to pending AAA/EAPOL message.
164 protected int cleanupTimerTimeOutInMins;
165
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100166 // Setup specific customization/attributes on the RADIUS packets
167 PacketCustomizer pktCustomizer;
Ray Milkey967776a2015-10-07 14:37:17 -0700168
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100169 // packet customizer to use
170 private String customizer;
171
172 // Type of connection to use to communicate with Radius server, options are
173 // "socket" or "packet_out"
174 private String radiusConnectionType;
175
Jonathan Hart5db44532018-07-12 18:13:54 -0700176 // Object for the specific type of communication with the RADIUS
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100177 // server, socket based or packet_out based
178 RadiusCommunicator impl = null;
179
180 // latest configuration
181 AaaConfig newCfg;
Ray Milkey967776a2015-10-07 14:37:17 -0700182
kartikey dubeye1545422019-05-22 12:53:45 +0000183 ScheduledFuture<?> scheduledFuture;
184
185 ScheduledExecutorService executor;
186 String configuredAaaServerAddress;
187 HashSet<Byte> outPacketSet = new HashSet<Byte>();
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000188 HashSet<Byte> outPacketSupp = new HashSet<Byte>();
189 static final List<Byte> VALID_EAPOL_TYPE = Arrays.asList(EAPOL.EAPOL_START, EAPOL.EAPOL_LOGOFF, EAPOL.EAPOL_PACKET);
190 static final int HEADER_LENGTH = 4;
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700191 // Configuration properties factory
192 private final ConfigFactory factory =
Jonathan Hart092dfb22015-11-16 23:05:21 -0800193 new ConfigFactory<ApplicationId, AaaConfig>(APP_SUBJECT_FACTORY,
194 AaaConfig.class,
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700195 "AAA") {
196 @Override
Jonathan Hart092dfb22015-11-16 23:05:21 -0800197 public AaaConfig createConfig() {
198 return new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700199 }
200 };
Ray Milkeyf51eba22015-09-25 10:24:23 -0700201
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700202 // Listener for config changes
203 private final InternalConfigListener cfgListener = new InternalConfigListener();
Ari Saha89831742015-06-26 10:31:48 -0700204
Jonathan Hart5db44532018-07-12 18:13:54 -0700205 private StateMachineDelegate delegate = new InternalStateMachineDelegate();
206
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700207 /**
208 * Builds an EAPOL packet based on the given parameters.
209 *
210 * @param dstMac destination MAC address
211 * @param srcMac source MAC address
212 * @param vlan vlan identifier
213 * @param eapolType EAPOL type
214 * @param eap EAP payload
215 * @return Ethernet frame
216 */
217 private static Ethernet buildEapolResponse(MacAddress dstMac, MacAddress srcMac,
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100218 short vlan, byte eapolType, EAP eap, byte priorityCode) {
Ari Saha89831742015-06-26 10:31:48 -0700219
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700220 Ethernet eth = new Ethernet();
221 eth.setDestinationMACAddress(dstMac.toBytes());
222 eth.setSourceMACAddress(srcMac.toBytes());
223 eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
224 if (vlan != Ethernet.VLAN_UNTAGGED) {
225 eth.setVlanID(vlan);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100226 eth.setPriorityCode(priorityCode);
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700227 }
228 //eapol header
229 EAPOL eapol = new EAPOL();
230 eapol.setEapolType(eapolType);
231 eapol.setPacketLength(eap.getLength());
Ari Saha89831742015-06-26 10:31:48 -0700232
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700233 //eap part
234 eapol.setPayload(eap);
235
236 eth.setPayload(eapol);
237 eth.setPad(true);
238 return eth;
239 }
Ari Saha89831742015-06-26 10:31:48 -0700240
Ari Saha89831742015-06-26 10:31:48 -0700241 @Activate
kartikey dubeye1545422019-05-22 12:53:45 +0000242 public void activate(ComponentContext context) {
Charles Chandf7ff862017-01-20 11:22:05 -0800243 appId = coreService.registerApplication(APP_NAME);
Jonathan Hart5db44532018-07-12 18:13:54 -0700244 eventDispatcher.addSink(AuthenticationEvent.class, listenerRegistry);
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400245 netCfgService.addListener(cfgListener);
246 netCfgService.registerConfigFactory(factory);
kartikey dubeye1545422019-05-22 12:53:45 +0000247 cfgService.registerProperties(getClass());
248 modified(context);
Gamze Abaka1cfdb192018-10-25 11:39:19 +0000249 subsService = sadisService.getSubscriberInfoService();
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530250 customInfo = new CustomizationInfo(subsService, deviceService);
Jonathan Hart092dfb22015-11-16 23:05:21 -0800251 cfgListener.reconfigureNetwork(netCfgService.getConfig(appId, AaaConfig.class));
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400252 log.info("Starting with config {} {}", this, newCfg);
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530253 configureRadiusCommunication();
Ari Saha89831742015-06-26 10:31:48 -0700254 // register our event handler
Brian O'Connord9c7da02015-07-29 17:49:24 -0700255 packetService.addProcessor(processor, PacketProcessor.director(2));
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700256 StateMachine.initializeMaps();
Jonathan Hart5db44532018-07-12 18:13:54 -0700257 StateMachine.setDelegate(delegate);
Shubham Sharma1e43c562019-06-19 14:18:12 +0000258 cleanupTimerTimeOutInMins = newCfg.sessionCleanupTimer();
259 StateMachine.setcleanupTimerTimeOutInMins(cleanupTimerTimeOutInMins);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100260 impl.initializeLocalState(newCfg);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100261 impl.requestIntercepts();
Amit Ghoshf739be52017-09-21 15:49:37 +0100262 deviceService.addListener(deviceListener);
kartikey dubeye1545422019-05-22 12:53:45 +0000263 getConfiguredAaaServerAddress();
264 authenticationStatisticsPublisher =
265 new AuthenticationStatisticsEventPublisher();
266 executor = Executors.newScheduledThreadPool(1);
267 scheduledFuture = executor.scheduleAtFixedRate(authenticationStatisticsPublisher,
268 0, statisticsGenerationEvent, TimeUnit.SECONDS);
Amit Ghoshf739be52017-09-21 15:49:37 +0100269
Jian Li13c67162015-12-09 13:20:34 -0800270 log.info("Started");
Ari Saha89831742015-06-26 10:31:48 -0700271 }
272
273 @Deactivate
kartikey dubeye1545422019-05-22 12:53:45 +0000274 public void deactivate(ComponentContext context) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100275 impl.withdrawIntercepts();
Ari Saha89831742015-06-26 10:31:48 -0700276 packetService.removeProcessor(processor);
Deepa Vaddireddyb9c24c62017-09-21 13:45:30 +0530277 netCfgService.removeListener(cfgListener);
kartikey dubeye1545422019-05-22 12:53:45 +0000278 cfgService.unregisterProperties(getClass(), false);
Jonathan Hart5db44532018-07-12 18:13:54 -0700279 StateMachine.unsetDelegate(delegate);
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530280 StateMachine.destroyMaps();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100281 impl.deactivate();
Amit Ghoshf739be52017-09-21 15:49:37 +0100282 deviceService.removeListener(deviceListener);
Jonathan Hart5db44532018-07-12 18:13:54 -0700283 eventDispatcher.removeSink(AuthenticationEvent.class);
kartikey dubeye1545422019-05-22 12:53:45 +0000284 scheduledFuture.cancel(true);
285 executor.shutdown();
Jian Li13c67162015-12-09 13:20:34 -0800286 log.info("Stopped");
Ray Milkey967776a2015-10-07 14:37:17 -0700287 }
288
kartikey dubeye1545422019-05-22 12:53:45 +0000289 @Modified
290 public void modified(ComponentContext context) {
291 Dictionary<?, ?> properties = context.getProperties();
Carmelo Cascone58b53292019-09-30 12:35:31 -0700292 String s = Tools.get(properties, STATISTICS_GENERATION_EVENT);
293 statisticsGenerationEvent = Strings.isNullOrEmpty(s)
294 ? STATISTICS_GENERATION_EVENT_DEFAULT : Integer.parseInt(s.trim());
kartikey dubeye1545422019-05-22 12:53:45 +0000295 }
296
Shubham Sharmacf5e5032019-11-26 11:09:21 +0000297 protected void configureRadiusCommunication() {
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530298 if (radiusConnectionType.toLowerCase().equals("socket")) {
299 impl = new SocketBasedRadiusCommunicator(appId, packetService, this);
300 } else {
301 impl = new PortBasedRadiusCommunicator(appId, packetService, mastershipService,
302 deviceService, subsService, pktCustomizer, this);
303 }
304 }
305
306 private void configurePacketCustomizer() {
307 switch (customizer.toLowerCase()) {
308 case "sample":
309 pktCustomizer = new SamplePacketCustomizer(customInfo);
310 log.info("Created SamplePacketCustomizer");
311 break;
Saurav Dase72358a2018-11-13 21:56:46 -0800312 case "att":
313 pktCustomizer = new AttPacketCustomizer(customInfo);
314 log.info("Created AttPacketCustomizer");
315 break;
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530316 default:
317 pktCustomizer = new PacketCustomizer(customInfo);
318 log.info("Created default PacketCustomizer");
319 break;
320 }
321 }
322
kartikey dubeye1545422019-05-22 12:53:45 +0000323 private void getConfiguredAaaServerAddress() {
324 try {
325 InetAddress address;
326 if (newCfg.radiusHostName() != null) {
327 address = InetAddress.getByName(newCfg.radiusHostName());
328 } else {
329 address = newCfg.radiusIp();
330 }
331
332 configuredAaaServerAddress = address.getHostAddress();
333 } catch (UnknownHostException uhe) {
334 log.warn("Unable to resolve host {}", newCfg.radiusHostName());
335 }
336 }
337
Vijaykumar Kushwaha056e4cd2019-08-06 13:16:25 +0000338 private void checkReceivedPacketForValidValidator(RADIUS radiusPacket, byte[] requestAuthenticator) {
339 if (!checkResponseMessageAuthenticator(radiusSecret, radiusPacket, requestAuthenticator)) {
kartikey dubeye1545422019-05-22 12:53:45 +0000340 aaaStatisticsManager.getAaaStats().increaseInvalidValidatorsRx();
341 }
342 }
Vijaykumar Kushwaha056e4cd2019-08-06 13:16:25 +0000343
344 private boolean checkResponseMessageAuthenticator(String key, RADIUS radiusPacket, byte[] requestAuthenticator) {
345 byte[] newHash = new byte[16];
346 Arrays.fill(newHash, (byte) 0);
347 byte[] messageAuthenticator = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH).getValue();
348 byte[] authenticator = radiusPacket.getAuthenticator();
349 radiusPacket.updateAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH, newHash);
350 radiusPacket.setAuthenticator(requestAuthenticator);
351 // Calculate the MD5 HMAC based on the message
352 try {
353 SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "HmacMD5");
354 Mac mac = Mac.getInstance("HmacMD5");
355 mac.init(keySpec);
356 newHash = mac.doFinal(radiusPacket.serialize());
357 } catch (Exception e) {
358 log.error("Failed to generate message authenticator: {}", e.getMessage());
359 }
360 radiusPacket.updateAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH, messageAuthenticator);
361 radiusPacket.setAuthenticator(authenticator);
362 // Compare the calculated Message-Authenticator with the one in the message
363 return Arrays.equals(newHash, messageAuthenticator);
364 }
kartikey dubeye1545422019-05-22 12:53:45 +0000365 public void checkForPacketFromUnknownServer(String hostAddress) {
366 if (!hostAddress.equals(configuredAaaServerAddress)) {
Vijaykumar Kushwahafffd3d12019-08-01 11:09:59 +0000367 getConfiguredAaaServerAddress();
368 if (!hostAddress.equals(configuredAaaServerAddress)) {
369 aaaStatisticsManager.getAaaStats().incrementUnknownServerRx();
370 }
kartikey dubeye1545422019-05-22 12:53:45 +0000371 }
372 }
373
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100374 /**
375 * Send RADIUS packet to the RADIUS server.
376 *
377 * @param radiusPacket RADIUS packet to be sent to server.
378 * @param inPkt Incoming EAPOL packet
379 */
380 protected void sendRadiusPacket(RADIUS radiusPacket, InboundPacket inPkt) {
kartikey dubeye1545422019-05-22 12:53:45 +0000381 outPacketSet.add(radiusPacket.getIdentifier());
382 aaaStatisticsManager.getAaaStats().increaseOrDecreasePendingRequests(true);
383 aaaStatisticsManager.getAaaStats().increaseAccessRequestsTx();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100384 impl.sendRadiusPacket(radiusPacket, inPkt);
385 }
Ray Milkey967776a2015-10-07 14:37:17 -0700386
Shubham Sharma1e43c562019-06-19 14:18:12 +0000387 /**
388 * For scheduling the timer required for cleaning up StateMachine
389 * when no response
390 * from RADIUS SERVER.
391 *
392 * @param sessionId SessionId of the current session
393 * @param stateMachine StateMachine for the id
394 */
395 public void scheduleStateMachineCleanupTimer(String sessionId, StateMachine stateMachine) {
396 StateMachine.CleanupTimerTask cleanupTask = stateMachine.new CleanupTimerTask(sessionId, this);
397 ScheduledFuture<?> cleanupTimer = executor.schedule(cleanupTask, cleanupTimerTimeOutInMins, TimeUnit.MINUTES);
398 stateMachine.setCleanupTimer(cleanupTimer);
399
400 }
401
402 /**
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100403 * Handles RADIUS packets.
404 *
405 * @param radiusPacket RADIUS packet coming from the RADIUS server.
406 * @throws StateMachineException if an illegal state transition is triggered
Jonathan Hart4731dd92018-05-02 17:30:05 -0700407 * @throws DeserializationException if packet deserialization fails
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100408 */
Jonathan Hart4731dd92018-05-02 17:30:05 -0700409 public void handleRadiusPacket(RADIUS radiusPacket)
410 throws StateMachineException, DeserializationException {
Saurav Das987441a2018-09-18 16:33:47 -0700411 if (log.isTraceEnabled()) {
412 log.trace("Received RADIUS packet {}", radiusPacket);
413 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100414 StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier());
415 if (stateMachine == null) {
Saurav Das987441a2018-09-18 16:33:47 -0700416 log.error("Invalid packet identifier {}, could not find corresponding "
417 + "state machine ... exiting", radiusPacket.getIdentifier());
kartikey dubeye1545422019-05-22 12:53:45 +0000418 aaaStatisticsManager.getAaaStats().incrementNumberOfSessionsExpired();
419 aaaStatisticsManager.getAaaStats().countDroppedResponsesRx();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100420 return;
Ray Milkey967776a2015-10-07 14:37:17 -0700421 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100422 EAP eapPayload;
423 Ethernet eth;
Vijaykumar Kushwaha056e4cd2019-08-06 13:16:25 +0000424 checkReceivedPacketForValidValidator(radiusPacket, stateMachine.requestAuthenticator());
kartikey dubeye1545422019-05-22 12:53:45 +0000425 if (outPacketSet.contains(radiusPacket.getIdentifier())) {
426 aaaStatisticsManager.getAaaStats().increaseOrDecreasePendingRequests(false);
427 outPacketSet.remove(new Byte(radiusPacket.getIdentifier()));
428 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100429 switch (radiusPacket.getCode()) {
430 case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400431 log.debug("RADIUS packet: RADIUS_CODE_ACCESS_CHALLENGE");
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100432 RADIUSAttribute radiusAttrState = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE);
433 byte[] challengeState = null;
434 if (radiusAttrState != null) {
435 challengeState = radiusAttrState.getValue();
436 }
437 eapPayload = radiusPacket.decapsulateMessage();
438 stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState);
439 eth = buildEapolResponse(stateMachine.supplicantAddress(),
440 MacAddress.valueOf(nasMacAddress),
441 stateMachine.vlanId(),
442 EAPOL.EAPOL_PACKET,
443 eapPayload, stateMachine.priorityCode());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400444 log.debug("Send EAP challenge response to supplicant {}", stateMachine.supplicantAddress().toString());
Shubham Sharma1f193582019-07-11 12:12:41 +0000445 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint(), true);
kartikey dubeye1545422019-05-22 12:53:45 +0000446 aaaStatisticsManager.getAaaStats().increaseChallengeResponsesRx();
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000447 outPacketSupp.add(eapPayload.getIdentifier());
448 aaaStatisticsManager.getAaaStats().incrementPendingResSupp();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100449 break;
450 case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400451 log.debug("RADIUS packet: RADIUS_CODE_ACCESS_ACCEPT");
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100452 //send an EAPOL - Success to the supplicant.
453 byte[] eapMessageSuccess =
454 radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
Jonathan Hart4731dd92018-05-02 17:30:05 -0700455 eapPayload = EAP.deserializer().deserialize(
456 eapMessageSuccess, 0, eapMessageSuccess.length);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100457 eth = buildEapolResponse(stateMachine.supplicantAddress(),
458 MacAddress.valueOf(nasMacAddress),
459 stateMachine.vlanId(),
460 EAPOL.EAPOL_PACKET,
461 eapPayload, stateMachine.priorityCode());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400462 log.info("Send EAP success message to supplicant {}", stateMachine.supplicantAddress().toString());
Shubham Sharma1f193582019-07-11 12:12:41 +0000463 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint(), false);
464 aaaStatisticsManager.getAaaStats().incrementEapolAuthSuccessTrans();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100465
466 stateMachine.authorizeAccess();
kartikey dubeye1545422019-05-22 12:53:45 +0000467 aaaStatisticsManager.getAaaStats().increaseAcceptResponsesRx();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100468 break;
469 case RADIUS.RADIUS_CODE_ACCESS_REJECT:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400470 log.debug("RADIUS packet: RADIUS_CODE_ACCESS_REJECT");
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100471 //send an EAPOL - Failure to the supplicant.
472 byte[] eapMessageFailure;
473 eapPayload = new EAP();
474 RADIUSAttribute radiusAttrEap = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE);
475 if (radiusAttrEap == null) {
476 eapPayload.setCode(EAP.FAILURE);
477 eapPayload.setIdentifier(stateMachine.challengeIdentifier());
478 eapPayload.setLength(EAP.EAP_HDR_LEN_SUC_FAIL);
479 } else {
480 eapMessageFailure = radiusAttrEap.getValue();
Jonathan Hart4731dd92018-05-02 17:30:05 -0700481 eapPayload = EAP.deserializer().deserialize(
482 eapMessageFailure, 0, eapMessageFailure.length);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100483 }
484 eth = buildEapolResponse(stateMachine.supplicantAddress(),
485 MacAddress.valueOf(nasMacAddress),
486 stateMachine.vlanId(),
487 EAPOL.EAPOL_PACKET,
488 eapPayload, stateMachine.priorityCode());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400489 log.warn("Send EAP failure message to supplicant {}", stateMachine.supplicantAddress().toString());
Shubham Sharma1f193582019-07-11 12:12:41 +0000490 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint(), false);
491 aaaStatisticsManager.getAaaStats().incrementEapolauthFailureTrans();
492
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100493 stateMachine.denyAccess();
kartikey dubeye1545422019-05-22 12:53:45 +0000494 aaaStatisticsManager.getAaaStats().increaseRejectResponsesRx();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100495 break;
496 default:
497 log.warn("Unknown RADIUS message received with code: {}", radiusPacket.getCode());
kartikey dubeye1545422019-05-22 12:53:45 +0000498 aaaStatisticsManager.getAaaStats().increaseUnknownTypeRx();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100499 }
kartikey dubeye1545422019-05-22 12:53:45 +0000500 aaaStatisticsManager.getAaaStats().countDroppedResponsesRx();
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700501 }
502
Ray Milkey967776a2015-10-07 14:37:17 -0700503 /**
504 * Send the ethernet packet to the supplicant.
505 *
506 * @param ethernetPkt the ethernet packet
507 * @param connectPoint the connect point to send out
508 */
Shubham Sharma1f193582019-07-11 12:12:41 +0000509 private void sendPacketToSupplicant(Ethernet ethernetPkt, ConnectPoint connectPoint, boolean isChallengeResponse) {
Ray Milkey967776a2015-10-07 14:37:17 -0700510 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
511 OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(),
512 treatment, ByteBuffer.wrap(ethernetPkt.serialize()));
Shubham Sharma1f193582019-07-11 12:12:41 +0000513 EAPOL eap = ((EAPOL) ethernetPkt.getPayload());
514 EAP eapPkt = (EAP) eap.getPayload();
Saurav Das987441a2018-09-18 16:33:47 -0700515 if (log.isTraceEnabled()) {
Saurav Das987441a2018-09-18 16:33:47 -0700516 log.trace("Sending eapol payload {} enclosed in {} to supplicant at {}",
517 eap, ethernetPkt, connectPoint);
518 }
Ray Milkey967776a2015-10-07 14:37:17 -0700519 packetService.emit(packet);
Shubham Sharma1f193582019-07-11 12:12:41 +0000520 if (isChallengeResponse) {
521 aaaStatisticsManager.getAaaStats().incrementEapPktTxauthEap();
522 }
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000523 aaaStatisticsManager.getAaaStats().incrementEapolFramesTx();
524 aaaStatisticsManager.getAaaStats().countReqEapFramesTx();
Ray Milkey967776a2015-10-07 14:37:17 -0700525 }
526
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400527 @Override
528 public String toString() {
529 return ToStringBuilder.reflectionToString(this);
530 }
531
Ari Saha89831742015-06-26 10:31:48 -0700532 // our handler defined as a private inner class
533
534 /**
535 * Packet processor responsible for forwarding packets along their paths.
536 */
537 private class ReactivePacketProcessor implements PacketProcessor {
538 @Override
539 public void process(PacketContext context) {
540
541 // Extract the original Ethernet frame from the packet information
542 InboundPacket pkt = context.inPacket();
543 Ethernet ethPkt = pkt.parsed();
544 if (ethPkt == null) {
545 return;
546 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100547
Ray Milkeyf51eba22015-09-25 10:24:23 -0700548 try {
549 // identify if incoming packet comes from supplicant (EAP) or RADIUS
550 switch (EthType.EtherType.lookup(ethPkt.getEtherType())) {
551 case EAPOL:
552 handleSupplicantPacket(context.inPacket());
553 break;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700554 default:
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100555 // any other packets let the specific implementation handle
556 impl.handlePacketFromServer(context);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700557 }
Ray Milkey967776a2015-10-07 14:37:17 -0700558 } catch (StateMachineException e) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100559 log.warn("Unable to process packet:", e);
Ari Saha89831742015-06-26 10:31:48 -0700560 }
561 }
562
Ray Milkey9eb293f2015-09-30 15:09:17 -0700563 /**
564 * Creates and initializes common fields of a RADIUS packet.
565 *
Ray Milkey967776a2015-10-07 14:37:17 -0700566 * @param stateMachine state machine for the request
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700567 * @param eapPacket EAP packet
Ray Milkey9eb293f2015-09-30 15:09:17 -0700568 * @return RADIUS packet
569 */
Ray Milkey967776a2015-10-07 14:37:17 -0700570 private RADIUS getRadiusPayload(StateMachine stateMachine, byte identifier, EAP eapPacket) {
Ray Milkey9eb293f2015-09-30 15:09:17 -0700571 RADIUS radiusPayload =
572 new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
573 eapPacket.getIdentifier());
Ray Milkey967776a2015-10-07 14:37:17 -0700574
575 // set Request Authenticator in StateMachine
576 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
577
Ray Milkey9eb293f2015-09-30 15:09:17 -0700578 radiusPayload.setIdentifier(identifier);
579 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
Ray Milkey967776a2015-10-07 14:37:17 -0700580 stateMachine.username());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700581
582 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
Jonathan Hart092dfb22015-11-16 23:05:21 -0800583 AaaManager.this.nasIpAddress.getAddress());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700584
585 radiusPayload.encapsulateMessage(eapPacket);
Ray Milkey9eb293f2015-09-30 15:09:17 -0700586
587 return radiusPayload;
588 }
Ari Saha89831742015-06-26 10:31:48 -0700589
590 /**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700591 * Handles PAE packets (supplicant).
592 *
593 * @param inPacket Ethernet packet coming from the supplicant
Ari Saha89831742015-06-26 10:31:48 -0700594 */
Ray Milkeyf51eba22015-09-25 10:24:23 -0700595 private void handleSupplicantPacket(InboundPacket inPacket) throws StateMachineException {
Jonathan Harta46dddf2015-06-30 15:31:20 -0700596 Ethernet ethPkt = inPacket.parsed();
Ari Saha89831742015-06-26 10:31:48 -0700597 // Where does it come from?
Jonathan Hart092dfb22015-11-16 23:05:21 -0800598 MacAddress srcMac = ethPkt.getSourceMAC();
Ari Saha89831742015-06-26 10:31:48 -0700599
Jonathan Harta46dddf2015-06-30 15:31:20 -0700600 DeviceId deviceId = inPacket.receivedFrom().deviceId();
601 PortNumber portNumber = inPacket.receivedFrom().port();
Ari Saha89831742015-06-26 10:31:48 -0700602 String sessionId = deviceId.toString() + portNumber.toString();
Saurav Das987441a2018-09-18 16:33:47 -0700603 EAPOL eapol = (EAPOL) ethPkt.getPayload();
604 if (log.isTraceEnabled()) {
605 log.trace("Received EAPOL packet {} in enclosing packet {} from "
606 + "dev/port: {}/{}", eapol, ethPkt, deviceId,
607 portNumber);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100608 }
Jonathan Harta46dddf2015-06-30 15:31:20 -0700609
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000610 short pktlen = eapol.getPacketLength();
611 byte[] eapPayLoadBuffer = eapol.serialize();
612 int len = eapPayLoadBuffer.length;
613 if (len != (HEADER_LENGTH + pktlen)) {
614 aaaStatisticsManager.getAaaStats().incrementInvalidBodyLength();
615 return;
616 }
617 if (!VALID_EAPOL_TYPE.contains(eapol.getEapolType())) {
618 aaaStatisticsManager.getAaaStats().incrementInvalidPktType();
619 return;
620 }
621 if (pktlen >= 0 && ethPkt.getEtherType() == EthType.EtherType.EAPOL.ethType().toShort()) {
622 aaaStatisticsManager.getAaaStats().incrementValidEapolFramesRx();
623 }
Saurav Das987441a2018-09-18 16:33:47 -0700624 StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
625 if (stateMachine == null) {
626 log.debug("Creating new state machine for sessionId: {} for "
627 + "dev/port: {}/{}", sessionId, deviceId, portNumber);
628 stateMachine = new StateMachine(sessionId);
629 } else {
630 log.debug("Using existing state-machine for sessionId: {}", sessionId);
631 }
632
Ari Saha89831742015-06-26 10:31:48 -0700633 switch (eapol.getEapolType()) {
634 case EAPOL.EAPOL_START:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400635 log.debug("EAP packet: EAPOL_START");
Ray Milkeyf51eba22015-09-25 10:24:23 -0700636 stateMachine.setSupplicantConnectpoint(inPacket.receivedFrom());
Shubham Sharma1e43c562019-06-19 14:18:12 +0000637 if (stateMachine.getCleanupTimer() == null) {
638 scheduleStateMachineCleanupTimer(sessionId, stateMachine);
639 }
Jonathan Hart5db44532018-07-12 18:13:54 -0700640 stateMachine.start();
Shubham Sharma1f193582019-07-11 12:12:41 +0000641 aaaStatisticsManager.getAaaStats().incrementEapolStartReqTrans();
Ray Milkeyf51eba22015-09-25 10:24:23 -0700642 //send an EAP Request/Identify to the supplicant
643 EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.identifier(), EAP.ATTR_IDENTITY, null);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100644 if (ethPkt.getVlanID() != Ethernet.VLAN_UNTAGGED) {
645 stateMachine.setPriorityCode(ethPkt.getPriorityCode());
646 }
Jonathan Hart092dfb22015-11-16 23:05:21 -0800647 Ethernet eth = buildEapolResponse(srcMac, MacAddress.valueOf(nasMacAddress),
Ray Milkeyf51eba22015-09-25 10:24:23 -0700648 ethPkt.getVlanID(), EAPOL.EAPOL_PACKET,
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100649 eapPayload, stateMachine.priorityCode());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400650
Jonathan Hart092dfb22015-11-16 23:05:21 -0800651 stateMachine.setSupplicantAddress(srcMac);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700652 stateMachine.setVlanId(ethPkt.getVlanID());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400653 log.debug("Getting EAP identity from supplicant {}", stateMachine.supplicantAddress().toString());
Shubham Sharma1f193582019-07-11 12:12:41 +0000654 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint(), false);
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000655 aaaStatisticsManager.getAaaStats().incrementRequestIdFramesTx();
Ari Saha89831742015-06-26 10:31:48 -0700656
657 break;
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800658 case EAPOL.EAPOL_LOGOFF:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400659 log.debug("EAP packet: EAPOL_LOGOFF");
Ray Milkeyb34b4962016-01-04 10:24:43 -0800660 if (stateMachine.state() == StateMachine.STATE_AUTHORIZED) {
661 stateMachine.logoff();
Shubham Sharma1f193582019-07-11 12:12:41 +0000662 aaaStatisticsManager.getAaaStats().incrementEapolLogoffRx();
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800663 }
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000664 if (stateMachine.state() == StateMachine.STATE_IDLE) {
665 aaaStatisticsManager.getAaaStats().incrementAuthStateIdle();
666 }
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800667
668 break;
Ari Saha89831742015-06-26 10:31:48 -0700669 case EAPOL.EAPOL_PACKET:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700670 RADIUS radiusPayload;
Ray Milkey9eb293f2015-09-30 15:09:17 -0700671 // check if this is a Response/Identify or a Response/TLS
Ari Saha89831742015-06-26 10:31:48 -0700672 EAP eapPacket = (EAP) eapol.getPayload();
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000673 Byte identifier = new Byte(eapPacket.getIdentifier());
Ari Saha89831742015-06-26 10:31:48 -0700674
675 byte dataType = eapPacket.getDataType();
676 switch (dataType) {
Ari Saha89831742015-06-26 10:31:48 -0700677
Ray Milkey9eb293f2015-09-30 15:09:17 -0700678 case EAP.ATTR_IDENTITY:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400679 log.debug("EAP packet: EAPOL_PACKET ATTR_IDENTITY");
Shubham Sharma1e43c562019-06-19 14:18:12 +0000680 //Setting the time of this response from RG, only when its not a re-transmission.
681 if (stateMachine.getLastPacketReceivedTime() == 0) {
682 stateMachine.setLastPacketReceivedTime(System.currentTimeMillis());
683 }
Ray Milkey9eb293f2015-09-30 15:09:17 -0700684 // request id access to RADIUS
685 stateMachine.setUsername(eapPacket.getData());
Ari Saha89831742015-06-26 10:31:48 -0700686
Ray Milkey967776a2015-10-07 14:37:17 -0700687 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100688 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Jonathan Hart092dfb22015-11-16 23:05:21 -0800689 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Ari Saha89831742015-06-26 10:31:48 -0700690
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100691 sendRadiusPacket(radiusPayload, inPacket);
Shubham Sharma1e43c562019-06-19 14:18:12 +0000692 stateMachine.setWaitingForRadiusResponse(true);
Shubham Sharma1f193582019-07-11 12:12:41 +0000693 aaaStatisticsManager.getAaaStats().incrementEapolAtrrIdentity();
Ray Milkey9eb293f2015-09-30 15:09:17 -0700694 // change the state to "PENDING"
kartikey dubeye1545422019-05-22 12:53:45 +0000695 if (stateMachine.state() == StateMachine.STATE_PENDING) {
696 aaaStatisticsManager.getAaaStats().increaseRequestReTx();
697 }
Ray Milkey9eb293f2015-09-30 15:09:17 -0700698 stateMachine.requestAccess();
699 break;
Ari Saha89831742015-06-26 10:31:48 -0700700 case EAP.ATTR_MD5:
Shubham Sharma1e43c562019-06-19 14:18:12 +0000701 stateMachine.setLastPacketReceivedTime(System.currentTimeMillis());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400702 log.debug("EAP packet: EAPOL_PACKET ATTR_MD5");
Ray Milkey9eb293f2015-09-30 15:09:17 -0700703 // verify if the EAP identifier corresponds to the
704 // challenge identifier from the client state
705 // machine.
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700706 if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) {
Ari Saha89831742015-06-26 10:31:48 -0700707 //send the RADIUS challenge response
Ray Milkey967776a2015-10-07 14:37:17 -0700708 radiusPayload =
709 getRadiusPayload(stateMachine,
710 stateMachine.identifier(),
711 eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100712 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700713
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800714 if (stateMachine.challengeState() != null) {
715 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
716 stateMachine.challengeState());
717 }
Jonathan Hart092dfb22015-11-16 23:05:21 -0800718 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000719 if (outPacketSupp.contains(eapPacket.getIdentifier())) {
720 aaaStatisticsManager.getAaaStats().decrementPendingResSupp();
721 outPacketSupp.remove(identifier);
722 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100723 sendRadiusPacket(radiusPayload, inPacket);
Shubham Sharma1e43c562019-06-19 14:18:12 +0000724 stateMachine.setWaitingForRadiusResponse(true);
Shubham Sharma1f193582019-07-11 12:12:41 +0000725 aaaStatisticsManager.getAaaStats().incrementEapolMd5RspChall();
Ari Saha89831742015-06-26 10:31:48 -0700726 }
727 break;
728 case EAP.ATTR_TLS:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400729 log.debug("EAP packet: EAPOL_PACKET ATTR_TLS");
Ray Milkey9eb293f2015-09-30 15:09:17 -0700730 // request id access to RADIUS
Ray Milkey967776a2015-10-07 14:37:17 -0700731 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100732 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700733
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800734 if (stateMachine.challengeState() != null) {
735 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
736 stateMachine.challengeState());
737 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700738 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
Ari Saha89831742015-06-26 10:31:48 -0700739
Jonathan Hart092dfb22015-11-16 23:05:21 -0800740 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000741 if (outPacketSupp.contains(eapPacket.getIdentifier())) {
742 aaaStatisticsManager.getAaaStats().decrementPendingResSupp();
743 outPacketSupp.remove(identifier);
744 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100745 sendRadiusPacket(radiusPayload, inPacket);
Shubham Sharma1e43c562019-06-19 14:18:12 +0000746 stateMachine.setWaitingForRadiusResponse(true);
Shubham Sharma1f193582019-07-11 12:12:41 +0000747 aaaStatisticsManager.getAaaStats().incrementEapolTlsRespChall();
Ray Milkey5493b512015-10-21 12:13:49 -0700748
Ray Milkeyf3790b82015-10-21 16:28:08 -0700749 if (stateMachine.state() != StateMachine.STATE_PENDING) {
750 stateMachine.requestAccess();
751 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700752
Ari Saha89831742015-06-26 10:31:48 -0700753 break;
754 default:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400755 log.warn("Unknown EAP packet type");
Ari Saha89831742015-06-26 10:31:48 -0700756 return;
757 }
758 break;
759 default:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400760 log.debug("Skipping EAPOL message {}", eapol.getEapolType());
Ari Saha89831742015-06-26 10:31:48 -0700761 }
Shubham Sharma1f193582019-07-11 12:12:41 +0000762 aaaStatisticsManager.getAaaStats().countTransRespNotNak();
763 aaaStatisticsManager.getAaaStats().countEapolResIdentityMsgTrans();
Ari Saha89831742015-06-26 10:31:48 -0700764 }
Ray Milkey967776a2015-10-07 14:37:17 -0700765 }
766
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100767 /**
Jonathan Hart5db44532018-07-12 18:13:54 -0700768 * Delegate allowing the StateMachine to notify us of events.
769 */
770 private class InternalStateMachineDelegate implements StateMachineDelegate {
771
772 @Override
773 public void notify(AuthenticationEvent authenticationEvent) {
774 log.info("Auth event {} for {}",
775 authenticationEvent.type(), authenticationEvent.subject());
776 post(authenticationEvent);
777 }
778 }
779
780 /**
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100781 * Configuration Listener, handles change in configuration.
782 */
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700783 private class InternalConfigListener implements NetworkConfigListener {
784
785 /**
Ray Milkeyc9e8dcc2015-12-30 10:31:32 -0800786 * Reconfigures the AAA application according to the
787 * configuration parameters passed.
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700788 *
789 * @param cfg configuration object
790 */
Jonathan Hart092dfb22015-11-16 23:05:21 -0800791 private void reconfigureNetwork(AaaConfig cfg) {
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400792 log.info("Reconfiguring AaaConfig from config: {}", cfg);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100793
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700794 if (cfg == null) {
Jonathan Hart092dfb22015-11-16 23:05:21 -0800795 newCfg = new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700796 } else {
797 newCfg = cfg;
798 }
799 if (newCfg.nasIp() != null) {
800 nasIpAddress = newCfg.nasIp();
801 }
802 if (newCfg.radiusIp() != null) {
803 radiusIpAddress = newCfg.radiusIp();
804 }
805 if (newCfg.radiusMac() != null) {
806 radiusMacAddress = newCfg.radiusMac();
807 }
808 if (newCfg.nasMac() != null) {
809 nasMacAddress = newCfg.nasMac();
810 }
811 if (newCfg.radiusSecret() != null) {
812 radiusSecret = newCfg.radiusSecret();
813 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100814
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530815 boolean reconfigureCustomizer = false;
816 if (customizer == null || !customizer.equals(newCfg.radiusPktCustomizer())) {
817 customizer = newCfg.radiusPktCustomizer();
818 configurePacketCustomizer();
819 reconfigureCustomizer = true;
820 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100821
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530822 if (radiusConnectionType == null
823 || reconfigureCustomizer
824 || !radiusConnectionType.equals(newCfg.radiusConnectionType())) {
825 radiusConnectionType = newCfg.radiusConnectionType();
826 if (impl != null) {
827 impl.withdrawIntercepts();
828 impl.clearLocalState();
829 }
830 configureRadiusCommunication();
831 impl.initializeLocalState(newCfg);
832 impl.requestIntercepts();
833 } else if (impl != null) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100834 impl.clearLocalState();
835 impl.initializeLocalState(newCfg);
Ray Milkey5d99bd12015-10-06 15:41:30 -0700836 }
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700837 }
838
839 @Override
840 public void event(NetworkConfigEvent event) {
841
842 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
843 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
Jonathan Hart092dfb22015-11-16 23:05:21 -0800844 event.configClass().equals(AaaConfig.class)) {
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700845
Jonathan Hart092dfb22015-11-16 23:05:21 -0800846 AaaConfig cfg = netCfgService.getConfig(appId, AaaConfig.class);
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700847 reconfigureNetwork(cfg);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100848
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400849 log.info("Reconfigured: {}", cfg.toString());
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700850 }
851 }
852 }
Amit Ghoshf739be52017-09-21 15:49:37 +0100853
854 private class InternalDeviceListener implements DeviceListener {
855 @Override
856 public void event(DeviceEvent event) {
857
858 switch (event.type()) {
859 case PORT_REMOVED:
860 DeviceId devId = event.subject().id();
861 PortNumber portNumber = event.port().number();
862 String sessionId = devId.toString() + portNumber.toString();
863
864 Map<String, StateMachine> sessionIdMap = StateMachine.sessionIdMap();
865 StateMachine removed = sessionIdMap.remove(sessionId);
866 if (removed != null) {
867 StateMachine.deleteStateMachineMapping(removed);
868 }
869
870 break;
871 default:
872 return;
873 }
874 }
875 }
kartikey dubeye1545422019-05-22 12:53:45 +0000876 private class AuthenticationStatisticsEventPublisher implements Runnable {
877 private final Logger log = getLogger(getClass());
878 public void run() {
879 log.info("Notifying AuthenticationStatisticsEvent");
880 aaaStatisticsManager.calculatePacketRoundtripTime();
881 log.debug("AcceptResponsesRx---" + aaaStatisticsManager.getAaaStats().getAcceptResponsesRx());
882 log.debug("AccessRequestsTx---" + aaaStatisticsManager.getAaaStats().getAccessRequestsTx());
883 log.debug("ChallengeResponsesRx---" + aaaStatisticsManager.getAaaStats().getChallengeResponsesRx());
884 log.debug("DroppedResponsesRx---" + aaaStatisticsManager.getAaaStats().getDroppedResponsesRx());
885 log.debug("InvalidValidatorsRx---" + aaaStatisticsManager.getAaaStats().getInvalidValidatorsRx());
886 log.debug("MalformedResponsesRx---" + aaaStatisticsManager.getAaaStats().getMalformedResponsesRx());
887 log.debug("PendingRequests---" + aaaStatisticsManager.getAaaStats().getPendingRequests());
888 log.debug("RejectResponsesRx---" + aaaStatisticsManager.getAaaStats().getRejectResponsesRx());
889 log.debug("RequestReTx---" + aaaStatisticsManager.getAaaStats().getRequestReTx());
890 log.debug("RequestRttMilis---" + aaaStatisticsManager.getAaaStats().getRequestRttMilis());
891 log.debug("UnknownServerRx---" + aaaStatisticsManager.getAaaStats().getUnknownServerRx());
892 log.debug("UnknownTypeRx---" + aaaStatisticsManager.getAaaStats().getUnknownTypeRx());
Shubham Sharma1e43c562019-06-19 14:18:12 +0000893 log.debug("TimedOutPackets----" + aaaStatisticsManager.getAaaStats().getTimedOutPackets());
Shubham Sharma1f193582019-07-11 12:12:41 +0000894 log.debug("EapolLogoffRx---" + aaaStatisticsManager.getAaaStats().getEapolLogoffRx());
895 log.debug("EapolAuthSuccessTrans---" + aaaStatisticsManager.getAaaStats().getEapolAuthSuccessTrans());
896 log.debug("EapolAuthFailureTrans---" +
897 aaaStatisticsManager.getAaaStats().getEapolAuthFailureTrans());
898 log.debug("EapolStartReqTrans---" +
899 aaaStatisticsManager.getAaaStats().getEapolStartReqTrans());
900 log.debug("EapolTransRespNotNak---" +
901 aaaStatisticsManager.getAaaStats().getEapolTransRespNotNak());
902 log.debug("EapPktTxauthChooseEap---" +
903 aaaStatisticsManager.getAaaStats().getEapPktTxauthChooseEap());
904 log.debug("EapolResIdentityMsgTrans---" +
905 aaaStatisticsManager.getAaaStats().getEapolResIdentityMsgTrans());
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000906 log.debug("EapolFramesTx---" + aaaStatisticsManager.getAaaStats().getEapolFramesTx());
907 log.debug("AuthStateIdle---" + aaaStatisticsManager.getAaaStats().getAuthStateIdle());
908 log.debug("RequestIdFramesTx---" + aaaStatisticsManager.getAaaStats().getRequestIdFramesTx());
909 log.debug("ReqEapFramesTx---" + aaaStatisticsManager.getAaaStats().getReqEapFramesTx());
910 log.debug("InvalidPktType---" + aaaStatisticsManager.getAaaStats().getInvalidPktType());
911 log.debug("InvalidBodyLength---" + aaaStatisticsManager.getAaaStats().getInvalidBodyLength());
912 log.debug("ValidEapolFramesRx---" + aaaStatisticsManager.getAaaStats().getValidEapolFramesRx());
913 log.debug("PendingResSupp---" + aaaStatisticsManager.getAaaStats().getPendingResSupp());
914 log.debug("ResIdEapFramesRx---" + aaaStatisticsManager.getAaaStats().getEapolattrIdentity());
kartikey dubeye1545422019-05-22 12:53:45 +0000915 aaaStatisticsManager.getStatsDelegate().
916 notify(new AuthenticationStatisticsEvent(AuthenticationStatisticsEvent.Type.STATS_UPDATE,
917 aaaStatisticsManager.getAaaStats()));
918 }
919 }
Ari Saha89831742015-06-26 10:31:48 -0700920}