blob: 0e819d9a741a109b68b4445121b726c449d70556 [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 Hart932bedc2018-07-12 13:46:09 -070019import org.apache.commons.lang3.builder.ToStringBuilder;
Jonathan Hart4731dd92018-05-02 17:30:05 -070020import org.onlab.packet.DeserializationException;
Jonathan Harta46dddf2015-06-30 15:31:20 -070021import org.onlab.packet.EAP;
22import org.onlab.packet.EAPOL;
23import org.onlab.packet.EthType;
Ari Saha89831742015-06-26 10:31:48 -070024import org.onlab.packet.Ethernet;
Ari Saha89831742015-06-26 10:31:48 -070025import org.onlab.packet.MacAddress;
Jonathan Harta46dddf2015-06-30 15:31:20 -070026import org.onlab.packet.RADIUS;
27import org.onlab.packet.RADIUSAttribute;
kartikey dubeye1545422019-05-22 12:53:45 +000028import org.onlab.util.Tools;
29import org.onosproject.cfg.ComponentConfigService;
Ari Saha89831742015-06-26 10:31:48 -070030import org.onosproject.core.ApplicationId;
31import org.onosproject.core.CoreService;
Jonathan Hart5db44532018-07-12 18:13:54 -070032import org.onosproject.event.AbstractListenerManager;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010033import org.onosproject.mastership.MastershipService;
Ari Saha89831742015-06-26 10:31:48 -070034import org.onosproject.net.ConnectPoint;
35import org.onosproject.net.DeviceId;
Ari Saha89831742015-06-26 10:31:48 -070036import org.onosproject.net.PortNumber;
Ray Milkeyfcb623d2015-10-01 16:48:18 -070037import org.onosproject.net.config.ConfigFactory;
38import org.onosproject.net.config.NetworkConfigEvent;
39import org.onosproject.net.config.NetworkConfigListener;
40import org.onosproject.net.config.NetworkConfigRegistry;
Amit Ghoshf739be52017-09-21 15:49:37 +010041import org.onosproject.net.device.DeviceEvent;
42import org.onosproject.net.device.DeviceListener;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010043import org.onosproject.net.device.DeviceService;
Ari Saha89831742015-06-26 10:31:48 -070044import org.onosproject.net.flow.DefaultTrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070045import org.onosproject.net.flow.TrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070046import org.onosproject.net.packet.DefaultOutboundPacket;
47import org.onosproject.net.packet.InboundPacket;
48import org.onosproject.net.packet.OutboundPacket;
49import org.onosproject.net.packet.PacketContext;
Ari Saha89831742015-06-26 10:31:48 -070050import org.onosproject.net.packet.PacketProcessor;
51import org.onosproject.net.packet.PacketService;
Matteo Scandolocf847b82019-04-26 15:00:00 -070052import org.opencord.aaa.AaaConfig;
53import org.opencord.aaa.AuthenticationEvent;
54import org.opencord.aaa.AuthenticationEventListener;
55import org.opencord.aaa.AuthenticationService;
kartikey dubeye1545422019-05-22 12:53:45 +000056import org.opencord.aaa.AuthenticationStatisticsEvent;
57import org.opencord.aaa.AuthenticationStatisticsService;
Matteo Scandolocf847b82019-04-26 15:00:00 -070058import org.opencord.aaa.RadiusCommunicator;
Shubham Sharma4900ce62019-06-19 14:18:50 +000059import org.opencord.aaa.RadiusOperationalStatusEvent;
60import org.opencord.aaa.RadiusOperationalStatusService;
61import org.opencord.aaa.RadiusOperationalStatusService.RadiusOperationalStatusEvaluationMode;
Matteo Scandolocf847b82019-04-26 15:00:00 -070062import org.opencord.aaa.StateMachineDelegate;
Gamze Abaka1cfdb192018-10-25 11:39:19 +000063import org.opencord.sadis.BaseInformationService;
64import org.opencord.sadis.SadisService;
65import org.opencord.sadis.SubscriberAndDeviceInformation;
kartikey dubeye1545422019-05-22 12:53:45 +000066import org.osgi.service.component.ComponentContext;
Carmelo Cascone58b53292019-09-30 12:35:31 -070067import org.osgi.service.component.annotations.Activate;
Shubham Sharma4900ce62019-06-19 14:18:50 +000068import org.osgi.service.component.annotations.Component;
69import org.osgi.service.component.annotations.Deactivate;
70import org.osgi.service.component.annotations.Modified;
71import org.osgi.service.component.annotations.Reference;
72import org.osgi.service.component.annotations.ReferenceCardinality;
Ari Saha89831742015-06-26 10:31:48 -070073import org.slf4j.Logger;
74
Shubham Sharma4900ce62019-06-19 14:18:50 +000075import javax.crypto.Mac;
76import javax.crypto.spec.SecretKeySpec;
77import java.net.InetAddress;
78import java.net.UnknownHostException;
79import java.nio.ByteBuffer;
80import java.util.Arrays;
81import java.util.Dictionary;
82import java.util.HashSet;
83import java.util.List;
84import java.util.Map;
kartikey dubeye1545422019-05-22 12:53:45 +000085import java.util.concurrent.Executors;
86import java.util.concurrent.ScheduledExecutorService;
87import java.util.concurrent.ScheduledFuture;
88import java.util.concurrent.TimeUnit;
Vijaykumar Kushwaha056e4cd2019-08-06 13:16:25 +000089
Shubham Sharma4900ce62019-06-19 14:18:50 +000090import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
91import static org.opencord.aaa.impl.OsgiPropertyConstants.OPERATIONAL_STATUS_SERVER_EVENT_GENERATION;
92import static org.opencord.aaa.impl.OsgiPropertyConstants.OPERATIONAL_STATUS_SERVER_EVENT_GENERATION_DEFAULT;
93import static org.opencord.aaa.impl.OsgiPropertyConstants.OPERATIONAL_STATUS_SERVER_TIMEOUT;
94import static org.opencord.aaa.impl.OsgiPropertyConstants.OPERATIONAL_STATUS_SERVER_TIMEOUT_DEFAULT;
95import static org.opencord.aaa.impl.OsgiPropertyConstants.STATISTICS_GENERATION_PERIOD;
96import static org.opencord.aaa.impl.OsgiPropertyConstants.STATISTICS_GENERATION_PERIOD_DEFAULT;
97import static org.opencord.aaa.impl.OsgiPropertyConstants.STATUS_SERVER_MODE;
98import static org.opencord.aaa.impl.OsgiPropertyConstants.STATUS_SERVER_MODE_DEFAULT;
99import static org.slf4j.LoggerFactory.getLogger;
Carmelo Cascone58b53292019-09-30 12:35:31 -0700100
Ari Saha89831742015-06-26 10:31:48 -0700101/**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700102 * AAA application for ONOS.
Ari Saha89831742015-06-26 10:31:48 -0700103 */
Carmelo Cascone58b53292019-09-30 12:35:31 -0700104@Component(immediate = true, property = {
Shubham Sharma4900ce62019-06-19 14:18:50 +0000105 STATISTICS_GENERATION_PERIOD + ":Integer=" + STATISTICS_GENERATION_PERIOD_DEFAULT,
106 OPERATIONAL_STATUS_SERVER_EVENT_GENERATION + ":Integer=" + OPERATIONAL_STATUS_SERVER_EVENT_GENERATION_DEFAULT,
107 OPERATIONAL_STATUS_SERVER_TIMEOUT + ":Integer=" + OPERATIONAL_STATUS_SERVER_TIMEOUT_DEFAULT,
108 STATUS_SERVER_MODE + ":String=" + STATUS_SERVER_MODE_DEFAULT,
Carmelo Cascone58b53292019-09-30 12:35:31 -0700109})
Jonathan Hart5db44532018-07-12 18:13:54 -0700110public class AaaManager
111 extends AbstractListenerManager<AuthenticationEvent, AuthenticationEventListener>
112 implements AuthenticationService {
113
Charles Chandf7ff862017-01-20 11:22:05 -0800114 private static final String APP_NAME = "org.opencord.aaa";
Ray Milkeyf51eba22015-09-25 10:24:23 -0700115
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700116 private final Logger log = getLogger(getClass());
Ray Milkeyf51eba22015-09-25 10:24:23 -0700117
Carmelo Cascone58b53292019-09-30 12:35:31 -0700118 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700119 protected CoreService coreService;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700120
Carmelo Cascone58b53292019-09-30 12:35:31 -0700121 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700122 protected PacketService packetService;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700123
Carmelo Cascone58b53292019-09-30 12:35:31 -0700124 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700125 protected NetworkConfigRegistry netCfgService;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700126
Carmelo Cascone58b53292019-09-30 12:35:31 -0700127 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100128 protected DeviceService deviceService;
129
Carmelo Cascone58b53292019-09-30 12:35:31 -0700130 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Gamze Abaka1cfdb192018-10-25 11:39:19 +0000131 protected SadisService sadisService;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100132
Carmelo Cascone58b53292019-09-30 12:35:31 -0700133 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100134 protected MastershipService mastershipService;
135
Carmelo Cascone58b53292019-09-30 12:35:31 -0700136 @Reference(cardinality = ReferenceCardinality.MANDATORY)
kartikey dubeye1545422019-05-22 12:53:45 +0000137 protected AuthenticationStatisticsService aaaStatisticsManager;
Gamze Abaka1cfdb192018-10-25 11:39:19 +0000138
Carmelo Cascone58b53292019-09-30 12:35:31 -0700139 @Reference(cardinality = ReferenceCardinality.MANDATORY)
kartikey dubeye1545422019-05-22 12:53:45 +0000140 protected ComponentConfigService cfgService;
141
Shubham Sharma4900ce62019-06-19 14:18:50 +0000142 @Reference(cardinality = ReferenceCardinality.MANDATORY)
143 protected RadiusOperationalStatusService radiusOperationalStatusService;
144
kartikey dubeye1545422019-05-22 12:53:45 +0000145 protected AuthenticationStatisticsEventPublisher authenticationStatisticsPublisher;
146 protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
Amit Ghoshf739be52017-09-21 15:49:37 +0100147 private final DeviceListener deviceListener = new InternalDeviceListener();
148
Shubham Sharma4900ce62019-06-19 14:18:50 +0000149 // Properties
150 private int statisticsGenerationPeriodInSeconds = STATISTICS_GENERATION_PERIOD_DEFAULT;
151 private int operationalStatusEventGenerationPeriodInSeconds = OPERATIONAL_STATUS_SERVER_EVENT_GENERATION_DEFAULT;
152 private int operationalStatusServerTimeoutInSeconds = OPERATIONAL_STATUS_SERVER_TIMEOUT_DEFAULT;
153 protected String operationalStatusEvaluationMode = STATUS_SERVER_MODE_DEFAULT;
kartikey dubeye1545422019-05-22 12:53:45 +0000154
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700155 // NAS IP address
156 protected InetAddress nasIpAddress;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100157
158 // self MAC address
Jonathan Hart5db44532018-07-12 18:13:54 -0700159 protected String nasMacAddress;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100160
161 // Parsed RADIUS server addresses
162 protected InetAddress radiusIpAddress;
163
164 // MAC address of RADIUS server or net hop router
165 protected String radiusMacAddress;
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700166
167 // RADIUS server secret
168 protected String radiusSecret;
169
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100170 // bindings
171 protected CustomizationInfo customInfo;
Ray Milkey5d99bd12015-10-06 15:41:30 -0700172
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700173 // our application-specific event handler
174 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
Ray Milkeyf51eba22015-09-25 10:24:23 -0700175
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700176 // our unique identifier
177 private ApplicationId appId;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700178
Shubham Sharma1e43c562019-06-19 14:18:12 +0000179 // TimeOut time for cleaning up stateMachines stuck due to pending AAA/EAPOL message.
180 protected int cleanupTimerTimeOutInMins;
181
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100182 // Setup specific customization/attributes on the RADIUS packets
183 PacketCustomizer pktCustomizer;
Ray Milkey967776a2015-10-07 14:37:17 -0700184
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100185 // packet customizer to use
186 private String customizer;
187
188 // Type of connection to use to communicate with Radius server, options are
189 // "socket" or "packet_out"
190 private String radiusConnectionType;
191
Jonathan Hart5db44532018-07-12 18:13:54 -0700192 // Object for the specific type of communication with the RADIUS
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100193 // server, socket based or packet_out based
194 RadiusCommunicator impl = null;
195
196 // latest configuration
197 AaaConfig newCfg;
Ray Milkey967776a2015-10-07 14:37:17 -0700198
kartikey dubeye1545422019-05-22 12:53:45 +0000199 ScheduledFuture<?> scheduledFuture;
Shubham Sharma4900ce62019-06-19 14:18:50 +0000200 ScheduledFuture<?> scheduledStatusServerChecker;
kartikey dubeye1545422019-05-22 12:53:45 +0000201 ScheduledExecutorService executor;
202 String configuredAaaServerAddress;
203 HashSet<Byte> outPacketSet = new HashSet<Byte>();
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000204 HashSet<Byte> outPacketSupp = new HashSet<Byte>();
205 static final List<Byte> VALID_EAPOL_TYPE = Arrays.asList(EAPOL.EAPOL_START, EAPOL.EAPOL_LOGOFF, EAPOL.EAPOL_PACKET);
206 static final int HEADER_LENGTH = 4;
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700207 // Configuration properties factory
208 private final ConfigFactory factory =
Jonathan Hart092dfb22015-11-16 23:05:21 -0800209 new ConfigFactory<ApplicationId, AaaConfig>(APP_SUBJECT_FACTORY,
210 AaaConfig.class,
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700211 "AAA") {
212 @Override
Jonathan Hart092dfb22015-11-16 23:05:21 -0800213 public AaaConfig createConfig() {
214 return new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700215 }
216 };
Ray Milkeyf51eba22015-09-25 10:24:23 -0700217
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700218 // Listener for config changes
219 private final InternalConfigListener cfgListener = new InternalConfigListener();
Ari Saha89831742015-06-26 10:31:48 -0700220
Jonathan Hart5db44532018-07-12 18:13:54 -0700221 private StateMachineDelegate delegate = new InternalStateMachineDelegate();
222
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700223 /**
224 * Builds an EAPOL packet based on the given parameters.
225 *
226 * @param dstMac destination MAC address
227 * @param srcMac source MAC address
228 * @param vlan vlan identifier
229 * @param eapolType EAPOL type
230 * @param eap EAP payload
231 * @return Ethernet frame
232 */
233 private static Ethernet buildEapolResponse(MacAddress dstMac, MacAddress srcMac,
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100234 short vlan, byte eapolType, EAP eap, byte priorityCode) {
Ari Saha89831742015-06-26 10:31:48 -0700235
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700236 Ethernet eth = new Ethernet();
237 eth.setDestinationMACAddress(dstMac.toBytes());
238 eth.setSourceMACAddress(srcMac.toBytes());
239 eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
240 if (vlan != Ethernet.VLAN_UNTAGGED) {
241 eth.setVlanID(vlan);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100242 eth.setPriorityCode(priorityCode);
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700243 }
244 //eapol header
245 EAPOL eapol = new EAPOL();
246 eapol.setEapolType(eapolType);
247 eapol.setPacketLength(eap.getLength());
Ari Saha89831742015-06-26 10:31:48 -0700248
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700249 //eap part
250 eapol.setPayload(eap);
251
252 eth.setPayload(eapol);
253 eth.setPad(true);
254 return eth;
255 }
Ari Saha89831742015-06-26 10:31:48 -0700256
Ari Saha89831742015-06-26 10:31:48 -0700257 @Activate
kartikey dubeye1545422019-05-22 12:53:45 +0000258 public void activate(ComponentContext context) {
Charles Chandf7ff862017-01-20 11:22:05 -0800259 appId = coreService.registerApplication(APP_NAME);
Jonathan Hart5db44532018-07-12 18:13:54 -0700260 eventDispatcher.addSink(AuthenticationEvent.class, listenerRegistry);
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400261 netCfgService.addListener(cfgListener);
262 netCfgService.registerConfigFactory(factory);
kartikey dubeye1545422019-05-22 12:53:45 +0000263 cfgService.registerProperties(getClass());
264 modified(context);
Gamze Abaka1cfdb192018-10-25 11:39:19 +0000265 subsService = sadisService.getSubscriberInfoService();
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530266 customInfo = new CustomizationInfo(subsService, deviceService);
Jonathan Hart092dfb22015-11-16 23:05:21 -0800267 cfgListener.reconfigureNetwork(netCfgService.getConfig(appId, AaaConfig.class));
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400268 log.info("Starting with config {} {}", this, newCfg);
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530269 configureRadiusCommunication();
Ari Saha89831742015-06-26 10:31:48 -0700270 // register our event handler
Brian O'Connord9c7da02015-07-29 17:49:24 -0700271 packetService.addProcessor(processor, PacketProcessor.director(2));
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700272 StateMachine.initializeMaps();
Jonathan Hart5db44532018-07-12 18:13:54 -0700273 StateMachine.setDelegate(delegate);
Shubham Sharma1e43c562019-06-19 14:18:12 +0000274 cleanupTimerTimeOutInMins = newCfg.sessionCleanupTimer();
275 StateMachine.setcleanupTimerTimeOutInMins(cleanupTimerTimeOutInMins);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100276 impl.initializeLocalState(newCfg);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100277 impl.requestIntercepts();
Amit Ghoshf739be52017-09-21 15:49:37 +0100278 deviceService.addListener(deviceListener);
kartikey dubeye1545422019-05-22 12:53:45 +0000279 getConfiguredAaaServerAddress();
Shubham Sharma4900ce62019-06-19 14:18:50 +0000280 radiusOperationalStatusService.initialize(nasIpAddress.getAddress(), radiusSecret, impl);
kartikey dubeye1545422019-05-22 12:53:45 +0000281 authenticationStatisticsPublisher =
282 new AuthenticationStatisticsEventPublisher();
Shubham Sharma4900ce62019-06-19 14:18:50 +0000283 executor = Executors.newScheduledThreadPool(3);
284
kartikey dubeye1545422019-05-22 12:53:45 +0000285 scheduledFuture = executor.scheduleAtFixedRate(authenticationStatisticsPublisher,
Shubham Sharma4900ce62019-06-19 14:18:50 +0000286 0, statisticsGenerationPeriodInSeconds, TimeUnit.SECONDS);
287 scheduledStatusServerChecker = executor.scheduleAtFixedRate(new ServerStatusChecker(), 0,
288 operationalStatusEventGenerationPeriodInSeconds, TimeUnit.SECONDS);
Amit Ghoshf739be52017-09-21 15:49:37 +0100289
Jian Li13c67162015-12-09 13:20:34 -0800290 log.info("Started");
Ari Saha89831742015-06-26 10:31:48 -0700291 }
292
293 @Deactivate
kartikey dubeye1545422019-05-22 12:53:45 +0000294 public void deactivate(ComponentContext context) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100295 impl.withdrawIntercepts();
Ari Saha89831742015-06-26 10:31:48 -0700296 packetService.removeProcessor(processor);
Deepa Vaddireddyb9c24c62017-09-21 13:45:30 +0530297 netCfgService.removeListener(cfgListener);
kartikey dubeye1545422019-05-22 12:53:45 +0000298 cfgService.unregisterProperties(getClass(), false);
Jonathan Hart5db44532018-07-12 18:13:54 -0700299 StateMachine.unsetDelegate(delegate);
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530300 StateMachine.destroyMaps();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100301 impl.deactivate();
Amit Ghoshf739be52017-09-21 15:49:37 +0100302 deviceService.removeListener(deviceListener);
Jonathan Hart5db44532018-07-12 18:13:54 -0700303 eventDispatcher.removeSink(AuthenticationEvent.class);
kartikey dubeye1545422019-05-22 12:53:45 +0000304 scheduledFuture.cancel(true);
Shubham Sharma4900ce62019-06-19 14:18:50 +0000305 scheduledStatusServerChecker.cancel(true);
kartikey dubeye1545422019-05-22 12:53:45 +0000306 executor.shutdown();
Jian Li13c67162015-12-09 13:20:34 -0800307 log.info("Stopped");
Ray Milkey967776a2015-10-07 14:37:17 -0700308 }
kartikey dubeye1545422019-05-22 12:53:45 +0000309 @Modified
310 public void modified(ComponentContext context) {
Shubham Sharma4900ce62019-06-19 14:18:50 +0000311 Dictionary<String, Object> properties = context.getProperties();
312
313 String s = Tools.get(properties, "statisticsGenerationPeriodInSeconds");
314 statisticsGenerationPeriodInSeconds = Strings.isNullOrEmpty(s) ? STATISTICS_GENERATION_PERIOD_DEFAULT
315 : Integer.parseInt(s.trim());
316
317 s = Tools.get(properties, "operationalStatusEventGenerationPeriodInSeconds");
318 operationalStatusEventGenerationPeriodInSeconds = Strings.isNullOrEmpty(s)
319 ? OPERATIONAL_STATUS_SERVER_EVENT_GENERATION_DEFAULT
320 : Integer.parseInt(s.trim());
321
322 s = Tools.get(properties, "operationalStatusServerTimeoutInSeconds");
323 operationalStatusServerTimeoutInSeconds = Strings.isNullOrEmpty(s) ? OPERATIONAL_STATUS_SERVER_TIMEOUT_DEFAULT
324 : Integer.parseInt(s.trim());
325
326 s = Tools.get(properties, "operationalStatusEvaluationMode");
327 String newEvaluationModeString = Strings.isNullOrEmpty(s) ? STATUS_SERVER_MODE_DEFAULT : s.trim();
328
329 radiusOperationalStatusService
330 .setOperationalStatusServerTimeoutInMillis(operationalStatusServerTimeoutInSeconds * 1000);
331 RadiusOperationalStatusEvaluationMode newEvaluationMode =
332 RadiusOperationalStatusEvaluationMode.getValue(newEvaluationModeString);
333 if (newEvaluationMode != null) {
334 radiusOperationalStatusService.setRadiusOperationalStatusEvaluationMode(newEvaluationMode);
335 operationalStatusEvaluationMode = newEvaluationModeString;
336 } else {
337 properties.put("operationalStatusEvaluationMode", operationalStatusEvaluationMode);
338 }
kartikey dubeye1545422019-05-22 12:53:45 +0000339 }
340
Shubham Sharmacf5e5032019-11-26 11:09:21 +0000341 protected void configureRadiusCommunication() {
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530342 if (radiusConnectionType.toLowerCase().equals("socket")) {
343 impl = new SocketBasedRadiusCommunicator(appId, packetService, this);
344 } else {
345 impl = new PortBasedRadiusCommunicator(appId, packetService, mastershipService,
346 deviceService, subsService, pktCustomizer, this);
347 }
348 }
349
350 private void configurePacketCustomizer() {
351 switch (customizer.toLowerCase()) {
352 case "sample":
353 pktCustomizer = new SamplePacketCustomizer(customInfo);
354 log.info("Created SamplePacketCustomizer");
355 break;
Saurav Dase72358a2018-11-13 21:56:46 -0800356 case "att":
357 pktCustomizer = new AttPacketCustomizer(customInfo);
358 log.info("Created AttPacketCustomizer");
359 break;
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530360 default:
361 pktCustomizer = new PacketCustomizer(customInfo);
362 log.info("Created default PacketCustomizer");
363 break;
364 }
365 }
366
kartikey dubeye1545422019-05-22 12:53:45 +0000367 private void getConfiguredAaaServerAddress() {
368 try {
369 InetAddress address;
370 if (newCfg.radiusHostName() != null) {
371 address = InetAddress.getByName(newCfg.radiusHostName());
372 } else {
373 address = newCfg.radiusIp();
374 }
375
376 configuredAaaServerAddress = address.getHostAddress();
377 } catch (UnknownHostException uhe) {
378 log.warn("Unable to resolve host {}", newCfg.radiusHostName());
379 }
380 }
381
Vijaykumar Kushwaha056e4cd2019-08-06 13:16:25 +0000382 private void checkReceivedPacketForValidValidator(RADIUS radiusPacket, byte[] requestAuthenticator) {
383 if (!checkResponseMessageAuthenticator(radiusSecret, radiusPacket, requestAuthenticator)) {
kartikey dubeye1545422019-05-22 12:53:45 +0000384 aaaStatisticsManager.getAaaStats().increaseInvalidValidatorsRx();
385 }
386 }
Vijaykumar Kushwaha056e4cd2019-08-06 13:16:25 +0000387
388 private boolean checkResponseMessageAuthenticator(String key, RADIUS radiusPacket, byte[] requestAuthenticator) {
389 byte[] newHash = new byte[16];
390 Arrays.fill(newHash, (byte) 0);
391 byte[] messageAuthenticator = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH).getValue();
392 byte[] authenticator = radiusPacket.getAuthenticator();
393 radiusPacket.updateAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH, newHash);
394 radiusPacket.setAuthenticator(requestAuthenticator);
395 // Calculate the MD5 HMAC based on the message
396 try {
397 SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "HmacMD5");
398 Mac mac = Mac.getInstance("HmacMD5");
399 mac.init(keySpec);
400 newHash = mac.doFinal(radiusPacket.serialize());
401 } catch (Exception e) {
402 log.error("Failed to generate message authenticator: {}", e.getMessage());
403 }
404 radiusPacket.updateAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH, messageAuthenticator);
405 radiusPacket.setAuthenticator(authenticator);
406 // Compare the calculated Message-Authenticator with the one in the message
407 return Arrays.equals(newHash, messageAuthenticator);
408 }
kartikey dubeye1545422019-05-22 12:53:45 +0000409 public void checkForPacketFromUnknownServer(String hostAddress) {
410 if (!hostAddress.equals(configuredAaaServerAddress)) {
Vijaykumar Kushwahafffd3d12019-08-01 11:09:59 +0000411 getConfiguredAaaServerAddress();
412 if (!hostAddress.equals(configuredAaaServerAddress)) {
413 aaaStatisticsManager.getAaaStats().incrementUnknownServerRx();
414 }
kartikey dubeye1545422019-05-22 12:53:45 +0000415 }
416 }
417
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100418 /**
419 * Send RADIUS packet to the RADIUS server.
420 *
421 * @param radiusPacket RADIUS packet to be sent to server.
422 * @param inPkt Incoming EAPOL packet
423 */
424 protected void sendRadiusPacket(RADIUS radiusPacket, InboundPacket inPkt) {
kartikey dubeye1545422019-05-22 12:53:45 +0000425 outPacketSet.add(radiusPacket.getIdentifier());
426 aaaStatisticsManager.getAaaStats().increaseOrDecreasePendingRequests(true);
427 aaaStatisticsManager.getAaaStats().increaseAccessRequestsTx();
Shubham Sharma4900ce62019-06-19 14:18:50 +0000428 aaaStatisticsManager.putOutgoingIdentifierToMap(radiusPacket.getIdentifier());
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100429 impl.sendRadiusPacket(radiusPacket, inPkt);
430 }
Ray Milkey967776a2015-10-07 14:37:17 -0700431
Shubham Sharma1e43c562019-06-19 14:18:12 +0000432 /**
433 * For scheduling the timer required for cleaning up StateMachine
434 * when no response
435 * from RADIUS SERVER.
436 *
437 * @param sessionId SessionId of the current session
438 * @param stateMachine StateMachine for the id
439 */
440 public void scheduleStateMachineCleanupTimer(String sessionId, StateMachine stateMachine) {
441 StateMachine.CleanupTimerTask cleanupTask = stateMachine.new CleanupTimerTask(sessionId, this);
442 ScheduledFuture<?> cleanupTimer = executor.schedule(cleanupTask, cleanupTimerTimeOutInMins, TimeUnit.MINUTES);
443 stateMachine.setCleanupTimer(cleanupTimer);
444
445 }
446
447 /**
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100448 * Handles RADIUS packets.
449 *
450 * @param radiusPacket RADIUS packet coming from the RADIUS server.
451 * @throws StateMachineException if an illegal state transition is triggered
Jonathan Hart4731dd92018-05-02 17:30:05 -0700452 * @throws DeserializationException if packet deserialization fails
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100453 */
Jonathan Hart4731dd92018-05-02 17:30:05 -0700454 public void handleRadiusPacket(RADIUS radiusPacket)
455 throws StateMachineException, DeserializationException {
Saurav Das987441a2018-09-18 16:33:47 -0700456 if (log.isTraceEnabled()) {
457 log.trace("Received RADIUS packet {}", radiusPacket);
458 }
Shubham Sharma4900ce62019-06-19 14:18:50 +0000459 if (radiusOperationalStatusService.isRadiusResponseForOperationalStatus(radiusPacket.getIdentifier())) {
460 radiusOperationalStatusService.handleRadiusPacketForOperationalStatus(radiusPacket);
461 return;
462 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100463 StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier());
464 if (stateMachine == null) {
Saurav Das987441a2018-09-18 16:33:47 -0700465 log.error("Invalid packet identifier {}, could not find corresponding "
466 + "state machine ... exiting", radiusPacket.getIdentifier());
kartikey dubeye1545422019-05-22 12:53:45 +0000467 aaaStatisticsManager.getAaaStats().incrementNumberOfSessionsExpired();
468 aaaStatisticsManager.getAaaStats().countDroppedResponsesRx();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100469 return;
Ray Milkey967776a2015-10-07 14:37:17 -0700470 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100471 EAP eapPayload;
472 Ethernet eth;
Vijaykumar Kushwaha056e4cd2019-08-06 13:16:25 +0000473 checkReceivedPacketForValidValidator(radiusPacket, stateMachine.requestAuthenticator());
kartikey dubeye1545422019-05-22 12:53:45 +0000474 if (outPacketSet.contains(radiusPacket.getIdentifier())) {
475 aaaStatisticsManager.getAaaStats().increaseOrDecreasePendingRequests(false);
476 outPacketSet.remove(new Byte(radiusPacket.getIdentifier()));
477 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100478 switch (radiusPacket.getCode()) {
479 case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400480 log.debug("RADIUS packet: RADIUS_CODE_ACCESS_CHALLENGE");
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100481 RADIUSAttribute radiusAttrState = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE);
482 byte[] challengeState = null;
483 if (radiusAttrState != null) {
484 challengeState = radiusAttrState.getValue();
485 }
486 eapPayload = radiusPacket.decapsulateMessage();
487 stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState);
488 eth = buildEapolResponse(stateMachine.supplicantAddress(),
489 MacAddress.valueOf(nasMacAddress),
490 stateMachine.vlanId(),
491 EAPOL.EAPOL_PACKET,
492 eapPayload, stateMachine.priorityCode());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400493 log.debug("Send EAP challenge response to supplicant {}", stateMachine.supplicantAddress().toString());
Shubham Sharma1f193582019-07-11 12:12:41 +0000494 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint(), true);
kartikey dubeye1545422019-05-22 12:53:45 +0000495 aaaStatisticsManager.getAaaStats().increaseChallengeResponsesRx();
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000496 outPacketSupp.add(eapPayload.getIdentifier());
497 aaaStatisticsManager.getAaaStats().incrementPendingResSupp();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100498 break;
499 case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400500 log.debug("RADIUS packet: RADIUS_CODE_ACCESS_ACCEPT");
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100501 //send an EAPOL - Success to the supplicant.
502 byte[] eapMessageSuccess =
503 radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
Jonathan Hart4731dd92018-05-02 17:30:05 -0700504 eapPayload = EAP.deserializer().deserialize(
505 eapMessageSuccess, 0, eapMessageSuccess.length);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100506 eth = buildEapolResponse(stateMachine.supplicantAddress(),
507 MacAddress.valueOf(nasMacAddress),
508 stateMachine.vlanId(),
509 EAPOL.EAPOL_PACKET,
510 eapPayload, stateMachine.priorityCode());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400511 log.info("Send EAP success message to supplicant {}", stateMachine.supplicantAddress().toString());
Shubham Sharma1f193582019-07-11 12:12:41 +0000512 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint(), false);
513 aaaStatisticsManager.getAaaStats().incrementEapolAuthSuccessTrans();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100514
515 stateMachine.authorizeAccess();
kartikey dubeye1545422019-05-22 12:53:45 +0000516 aaaStatisticsManager.getAaaStats().increaseAcceptResponsesRx();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100517 break;
518 case RADIUS.RADIUS_CODE_ACCESS_REJECT:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400519 log.debug("RADIUS packet: RADIUS_CODE_ACCESS_REJECT");
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100520 //send an EAPOL - Failure to the supplicant.
521 byte[] eapMessageFailure;
522 eapPayload = new EAP();
523 RADIUSAttribute radiusAttrEap = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE);
524 if (radiusAttrEap == null) {
525 eapPayload.setCode(EAP.FAILURE);
526 eapPayload.setIdentifier(stateMachine.challengeIdentifier());
527 eapPayload.setLength(EAP.EAP_HDR_LEN_SUC_FAIL);
528 } else {
529 eapMessageFailure = radiusAttrEap.getValue();
Jonathan Hart4731dd92018-05-02 17:30:05 -0700530 eapPayload = EAP.deserializer().deserialize(
531 eapMessageFailure, 0, eapMessageFailure.length);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100532 }
533 eth = buildEapolResponse(stateMachine.supplicantAddress(),
534 MacAddress.valueOf(nasMacAddress),
535 stateMachine.vlanId(),
536 EAPOL.EAPOL_PACKET,
537 eapPayload, stateMachine.priorityCode());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400538 log.warn("Send EAP failure message to supplicant {}", stateMachine.supplicantAddress().toString());
Shubham Sharma1f193582019-07-11 12:12:41 +0000539 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint(), false);
540 aaaStatisticsManager.getAaaStats().incrementEapolauthFailureTrans();
541
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100542 stateMachine.denyAccess();
kartikey dubeye1545422019-05-22 12:53:45 +0000543 aaaStatisticsManager.getAaaStats().increaseRejectResponsesRx();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100544 break;
545 default:
546 log.warn("Unknown RADIUS message received with code: {}", radiusPacket.getCode());
kartikey dubeye1545422019-05-22 12:53:45 +0000547 aaaStatisticsManager.getAaaStats().increaseUnknownTypeRx();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100548 }
kartikey dubeye1545422019-05-22 12:53:45 +0000549 aaaStatisticsManager.getAaaStats().countDroppedResponsesRx();
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700550 }
551
Ray Milkey967776a2015-10-07 14:37:17 -0700552 /**
553 * Send the ethernet packet to the supplicant.
554 *
555 * @param ethernetPkt the ethernet packet
556 * @param connectPoint the connect point to send out
557 */
Shubham Sharma1f193582019-07-11 12:12:41 +0000558 private void sendPacketToSupplicant(Ethernet ethernetPkt, ConnectPoint connectPoint, boolean isChallengeResponse) {
Ray Milkey967776a2015-10-07 14:37:17 -0700559 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
560 OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(),
561 treatment, ByteBuffer.wrap(ethernetPkt.serialize()));
Shubham Sharma1f193582019-07-11 12:12:41 +0000562 EAPOL eap = ((EAPOL) ethernetPkt.getPayload());
563 EAP eapPkt = (EAP) eap.getPayload();
Saurav Das987441a2018-09-18 16:33:47 -0700564 if (log.isTraceEnabled()) {
Saurav Das987441a2018-09-18 16:33:47 -0700565 log.trace("Sending eapol payload {} enclosed in {} to supplicant at {}",
566 eap, ethernetPkt, connectPoint);
567 }
Ray Milkey967776a2015-10-07 14:37:17 -0700568 packetService.emit(packet);
Shubham Sharma1f193582019-07-11 12:12:41 +0000569 if (isChallengeResponse) {
570 aaaStatisticsManager.getAaaStats().incrementEapPktTxauthEap();
571 }
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000572 aaaStatisticsManager.getAaaStats().incrementEapolFramesTx();
573 aaaStatisticsManager.getAaaStats().countReqEapFramesTx();
Ray Milkey967776a2015-10-07 14:37:17 -0700574 }
575
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400576 @Override
577 public String toString() {
578 return ToStringBuilder.reflectionToString(this);
579 }
580
Ari Saha89831742015-06-26 10:31:48 -0700581 // our handler defined as a private inner class
582
583 /**
584 * Packet processor responsible for forwarding packets along their paths.
585 */
586 private class ReactivePacketProcessor implements PacketProcessor {
587 @Override
588 public void process(PacketContext context) {
589
590 // Extract the original Ethernet frame from the packet information
591 InboundPacket pkt = context.inPacket();
592 Ethernet ethPkt = pkt.parsed();
593 if (ethPkt == null) {
594 return;
595 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100596
Ray Milkeyf51eba22015-09-25 10:24:23 -0700597 try {
598 // identify if incoming packet comes from supplicant (EAP) or RADIUS
599 switch (EthType.EtherType.lookup(ethPkt.getEtherType())) {
600 case EAPOL:
601 handleSupplicantPacket(context.inPacket());
602 break;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700603 default:
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100604 // any other packets let the specific implementation handle
605 impl.handlePacketFromServer(context);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700606 }
Ray Milkey967776a2015-10-07 14:37:17 -0700607 } catch (StateMachineException e) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100608 log.warn("Unable to process packet:", e);
Ari Saha89831742015-06-26 10:31:48 -0700609 }
610 }
611
Ray Milkey9eb293f2015-09-30 15:09:17 -0700612 /**
613 * Creates and initializes common fields of a RADIUS packet.
614 *
Ray Milkey967776a2015-10-07 14:37:17 -0700615 * @param stateMachine state machine for the request
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700616 * @param eapPacket EAP packet
Ray Milkey9eb293f2015-09-30 15:09:17 -0700617 * @return RADIUS packet
618 */
Ray Milkey967776a2015-10-07 14:37:17 -0700619 private RADIUS getRadiusPayload(StateMachine stateMachine, byte identifier, EAP eapPacket) {
Ray Milkey9eb293f2015-09-30 15:09:17 -0700620 RADIUS radiusPayload =
621 new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
622 eapPacket.getIdentifier());
Ray Milkey967776a2015-10-07 14:37:17 -0700623
624 // set Request Authenticator in StateMachine
625 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
626
Ray Milkey9eb293f2015-09-30 15:09:17 -0700627 radiusPayload.setIdentifier(identifier);
628 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
Ray Milkey967776a2015-10-07 14:37:17 -0700629 stateMachine.username());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700630
631 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
Jonathan Hart092dfb22015-11-16 23:05:21 -0800632 AaaManager.this.nasIpAddress.getAddress());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700633
634 radiusPayload.encapsulateMessage(eapPacket);
Ray Milkey9eb293f2015-09-30 15:09:17 -0700635
636 return radiusPayload;
637 }
Ari Saha89831742015-06-26 10:31:48 -0700638
639 /**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700640 * Handles PAE packets (supplicant).
641 *
642 * @param inPacket Ethernet packet coming from the supplicant
Ari Saha89831742015-06-26 10:31:48 -0700643 */
Ray Milkeyf51eba22015-09-25 10:24:23 -0700644 private void handleSupplicantPacket(InboundPacket inPacket) throws StateMachineException {
Jonathan Harta46dddf2015-06-30 15:31:20 -0700645 Ethernet ethPkt = inPacket.parsed();
Ari Saha89831742015-06-26 10:31:48 -0700646 // Where does it come from?
Jonathan Hart092dfb22015-11-16 23:05:21 -0800647 MacAddress srcMac = ethPkt.getSourceMAC();
Ari Saha89831742015-06-26 10:31:48 -0700648
Jonathan Harta46dddf2015-06-30 15:31:20 -0700649 DeviceId deviceId = inPacket.receivedFrom().deviceId();
650 PortNumber portNumber = inPacket.receivedFrom().port();
Ari Saha89831742015-06-26 10:31:48 -0700651 String sessionId = deviceId.toString() + portNumber.toString();
Saurav Das987441a2018-09-18 16:33:47 -0700652 EAPOL eapol = (EAPOL) ethPkt.getPayload();
653 if (log.isTraceEnabled()) {
654 log.trace("Received EAPOL packet {} in enclosing packet {} from "
655 + "dev/port: {}/{}", eapol, ethPkt, deviceId,
656 portNumber);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100657 }
Jonathan Harta46dddf2015-06-30 15:31:20 -0700658
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000659 short pktlen = eapol.getPacketLength();
660 byte[] eapPayLoadBuffer = eapol.serialize();
661 int len = eapPayLoadBuffer.length;
662 if (len != (HEADER_LENGTH + pktlen)) {
663 aaaStatisticsManager.getAaaStats().incrementInvalidBodyLength();
664 return;
665 }
666 if (!VALID_EAPOL_TYPE.contains(eapol.getEapolType())) {
667 aaaStatisticsManager.getAaaStats().incrementInvalidPktType();
668 return;
669 }
670 if (pktlen >= 0 && ethPkt.getEtherType() == EthType.EtherType.EAPOL.ethType().toShort()) {
671 aaaStatisticsManager.getAaaStats().incrementValidEapolFramesRx();
672 }
Saurav Das987441a2018-09-18 16:33:47 -0700673 StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
674 if (stateMachine == null) {
675 log.debug("Creating new state machine for sessionId: {} for "
676 + "dev/port: {}/{}", sessionId, deviceId, portNumber);
677 stateMachine = new StateMachine(sessionId);
678 } else {
679 log.debug("Using existing state-machine for sessionId: {}", sessionId);
680 }
681
Ari Saha89831742015-06-26 10:31:48 -0700682 switch (eapol.getEapolType()) {
683 case EAPOL.EAPOL_START:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400684 log.debug("EAP packet: EAPOL_START");
Ray Milkeyf51eba22015-09-25 10:24:23 -0700685 stateMachine.setSupplicantConnectpoint(inPacket.receivedFrom());
Shubham Sharma1e43c562019-06-19 14:18:12 +0000686 if (stateMachine.getCleanupTimer() == null) {
687 scheduleStateMachineCleanupTimer(sessionId, stateMachine);
688 }
Jonathan Hart5db44532018-07-12 18:13:54 -0700689 stateMachine.start();
Shubham Sharma1f193582019-07-11 12:12:41 +0000690 aaaStatisticsManager.getAaaStats().incrementEapolStartReqTrans();
Ray Milkeyf51eba22015-09-25 10:24:23 -0700691 //send an EAP Request/Identify to the supplicant
692 EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.identifier(), EAP.ATTR_IDENTITY, null);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100693 if (ethPkt.getVlanID() != Ethernet.VLAN_UNTAGGED) {
694 stateMachine.setPriorityCode(ethPkt.getPriorityCode());
695 }
Jonathan Hart092dfb22015-11-16 23:05:21 -0800696 Ethernet eth = buildEapolResponse(srcMac, MacAddress.valueOf(nasMacAddress),
Ray Milkeyf51eba22015-09-25 10:24:23 -0700697 ethPkt.getVlanID(), EAPOL.EAPOL_PACKET,
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100698 eapPayload, stateMachine.priorityCode());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400699
Jonathan Hart092dfb22015-11-16 23:05:21 -0800700 stateMachine.setSupplicantAddress(srcMac);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700701 stateMachine.setVlanId(ethPkt.getVlanID());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400702 log.debug("Getting EAP identity from supplicant {}", stateMachine.supplicantAddress().toString());
Shubham Sharma1f193582019-07-11 12:12:41 +0000703 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint(), false);
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000704 aaaStatisticsManager.getAaaStats().incrementRequestIdFramesTx();
Ari Saha89831742015-06-26 10:31:48 -0700705
706 break;
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800707 case EAPOL.EAPOL_LOGOFF:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400708 log.debug("EAP packet: EAPOL_LOGOFF");
Ray Milkeyb34b4962016-01-04 10:24:43 -0800709 if (stateMachine.state() == StateMachine.STATE_AUTHORIZED) {
710 stateMachine.logoff();
Shubham Sharma1f193582019-07-11 12:12:41 +0000711 aaaStatisticsManager.getAaaStats().incrementEapolLogoffRx();
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800712 }
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000713 if (stateMachine.state() == StateMachine.STATE_IDLE) {
714 aaaStatisticsManager.getAaaStats().incrementAuthStateIdle();
715 }
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800716
717 break;
Ari Saha89831742015-06-26 10:31:48 -0700718 case EAPOL.EAPOL_PACKET:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700719 RADIUS radiusPayload;
Ray Milkey9eb293f2015-09-30 15:09:17 -0700720 // check if this is a Response/Identify or a Response/TLS
Ari Saha89831742015-06-26 10:31:48 -0700721 EAP eapPacket = (EAP) eapol.getPayload();
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000722 Byte identifier = new Byte(eapPacket.getIdentifier());
Ari Saha89831742015-06-26 10:31:48 -0700723
724 byte dataType = eapPacket.getDataType();
725 switch (dataType) {
Ari Saha89831742015-06-26 10:31:48 -0700726
Ray Milkey9eb293f2015-09-30 15:09:17 -0700727 case EAP.ATTR_IDENTITY:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400728 log.debug("EAP packet: EAPOL_PACKET ATTR_IDENTITY");
Shubham Sharma1e43c562019-06-19 14:18:12 +0000729 //Setting the time of this response from RG, only when its not a re-transmission.
730 if (stateMachine.getLastPacketReceivedTime() == 0) {
731 stateMachine.setLastPacketReceivedTime(System.currentTimeMillis());
732 }
Ray Milkey9eb293f2015-09-30 15:09:17 -0700733 // request id access to RADIUS
734 stateMachine.setUsername(eapPacket.getData());
Ari Saha89831742015-06-26 10:31:48 -0700735
Ray Milkey967776a2015-10-07 14:37:17 -0700736 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100737 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Jonathan Hart092dfb22015-11-16 23:05:21 -0800738 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Ari Saha89831742015-06-26 10:31:48 -0700739
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100740 sendRadiusPacket(radiusPayload, inPacket);
Shubham Sharma1e43c562019-06-19 14:18:12 +0000741 stateMachine.setWaitingForRadiusResponse(true);
Shubham Sharma1f193582019-07-11 12:12:41 +0000742 aaaStatisticsManager.getAaaStats().incrementEapolAtrrIdentity();
Ray Milkey9eb293f2015-09-30 15:09:17 -0700743 // change the state to "PENDING"
kartikey dubeye1545422019-05-22 12:53:45 +0000744 if (stateMachine.state() == StateMachine.STATE_PENDING) {
745 aaaStatisticsManager.getAaaStats().increaseRequestReTx();
746 }
Ray Milkey9eb293f2015-09-30 15:09:17 -0700747 stateMachine.requestAccess();
748 break;
Ari Saha89831742015-06-26 10:31:48 -0700749 case EAP.ATTR_MD5:
Shubham Sharma1e43c562019-06-19 14:18:12 +0000750 stateMachine.setLastPacketReceivedTime(System.currentTimeMillis());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400751 log.debug("EAP packet: EAPOL_PACKET ATTR_MD5");
Ray Milkey9eb293f2015-09-30 15:09:17 -0700752 // verify if the EAP identifier corresponds to the
753 // challenge identifier from the client state
754 // machine.
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700755 if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) {
Ari Saha89831742015-06-26 10:31:48 -0700756 //send the RADIUS challenge response
Ray Milkey967776a2015-10-07 14:37:17 -0700757 radiusPayload =
758 getRadiusPayload(stateMachine,
759 stateMachine.identifier(),
760 eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100761 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700762
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800763 if (stateMachine.challengeState() != null) {
764 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
765 stateMachine.challengeState());
766 }
Jonathan Hart092dfb22015-11-16 23:05:21 -0800767 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000768 if (outPacketSupp.contains(eapPacket.getIdentifier())) {
769 aaaStatisticsManager.getAaaStats().decrementPendingResSupp();
770 outPacketSupp.remove(identifier);
771 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100772 sendRadiusPacket(radiusPayload, inPacket);
Shubham Sharma1e43c562019-06-19 14:18:12 +0000773 stateMachine.setWaitingForRadiusResponse(true);
Shubham Sharma1f193582019-07-11 12:12:41 +0000774 aaaStatisticsManager.getAaaStats().incrementEapolMd5RspChall();
Ari Saha89831742015-06-26 10:31:48 -0700775 }
776 break;
777 case EAP.ATTR_TLS:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400778 log.debug("EAP packet: EAPOL_PACKET ATTR_TLS");
Ray Milkey9eb293f2015-09-30 15:09:17 -0700779 // request id access to RADIUS
Ray Milkey967776a2015-10-07 14:37:17 -0700780 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100781 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700782
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800783 if (stateMachine.challengeState() != null) {
784 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
785 stateMachine.challengeState());
786 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700787 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
Ari Saha89831742015-06-26 10:31:48 -0700788
Jonathan Hart092dfb22015-11-16 23:05:21 -0800789 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000790 if (outPacketSupp.contains(eapPacket.getIdentifier())) {
791 aaaStatisticsManager.getAaaStats().decrementPendingResSupp();
792 outPacketSupp.remove(identifier);
793 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100794 sendRadiusPacket(radiusPayload, inPacket);
Shubham Sharma1e43c562019-06-19 14:18:12 +0000795 stateMachine.setWaitingForRadiusResponse(true);
Shubham Sharma1f193582019-07-11 12:12:41 +0000796 aaaStatisticsManager.getAaaStats().incrementEapolTlsRespChall();
Ray Milkey5493b512015-10-21 12:13:49 -0700797
Ray Milkeyf3790b82015-10-21 16:28:08 -0700798 if (stateMachine.state() != StateMachine.STATE_PENDING) {
799 stateMachine.requestAccess();
800 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700801
Ari Saha89831742015-06-26 10:31:48 -0700802 break;
803 default:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400804 log.warn("Unknown EAP packet type");
Ari Saha89831742015-06-26 10:31:48 -0700805 return;
806 }
807 break;
808 default:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400809 log.debug("Skipping EAPOL message {}", eapol.getEapolType());
Ari Saha89831742015-06-26 10:31:48 -0700810 }
Shubham Sharma1f193582019-07-11 12:12:41 +0000811 aaaStatisticsManager.getAaaStats().countTransRespNotNak();
812 aaaStatisticsManager.getAaaStats().countEapolResIdentityMsgTrans();
Ari Saha89831742015-06-26 10:31:48 -0700813 }
Ray Milkey967776a2015-10-07 14:37:17 -0700814 }
815
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100816 /**
Jonathan Hart5db44532018-07-12 18:13:54 -0700817 * Delegate allowing the StateMachine to notify us of events.
818 */
819 private class InternalStateMachineDelegate implements StateMachineDelegate {
820
821 @Override
822 public void notify(AuthenticationEvent authenticationEvent) {
823 log.info("Auth event {} for {}",
824 authenticationEvent.type(), authenticationEvent.subject());
825 post(authenticationEvent);
826 }
827 }
828
829 /**
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100830 * Configuration Listener, handles change in configuration.
831 */
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700832 private class InternalConfigListener implements NetworkConfigListener {
833
834 /**
Ray Milkeyc9e8dcc2015-12-30 10:31:32 -0800835 * Reconfigures the AAA application according to the
836 * configuration parameters passed.
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700837 *
838 * @param cfg configuration object
839 */
Jonathan Hart092dfb22015-11-16 23:05:21 -0800840 private void reconfigureNetwork(AaaConfig cfg) {
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400841 log.info("Reconfiguring AaaConfig from config: {}", cfg);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100842
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700843 if (cfg == null) {
Jonathan Hart092dfb22015-11-16 23:05:21 -0800844 newCfg = new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700845 } else {
846 newCfg = cfg;
847 }
848 if (newCfg.nasIp() != null) {
849 nasIpAddress = newCfg.nasIp();
850 }
851 if (newCfg.radiusIp() != null) {
852 radiusIpAddress = newCfg.radiusIp();
853 }
854 if (newCfg.radiusMac() != null) {
855 radiusMacAddress = newCfg.radiusMac();
856 }
857 if (newCfg.nasMac() != null) {
858 nasMacAddress = newCfg.nasMac();
859 }
860 if (newCfg.radiusSecret() != null) {
861 radiusSecret = newCfg.radiusSecret();
862 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100863
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530864 boolean reconfigureCustomizer = false;
865 if (customizer == null || !customizer.equals(newCfg.radiusPktCustomizer())) {
866 customizer = newCfg.radiusPktCustomizer();
867 configurePacketCustomizer();
868 reconfigureCustomizer = true;
869 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100870
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530871 if (radiusConnectionType == null
872 || reconfigureCustomizer
873 || !radiusConnectionType.equals(newCfg.radiusConnectionType())) {
874 radiusConnectionType = newCfg.radiusConnectionType();
875 if (impl != null) {
876 impl.withdrawIntercepts();
877 impl.clearLocalState();
878 }
879 configureRadiusCommunication();
880 impl.initializeLocalState(newCfg);
881 impl.requestIntercepts();
882 } else if (impl != null) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100883 impl.clearLocalState();
884 impl.initializeLocalState(newCfg);
Ray Milkey5d99bd12015-10-06 15:41:30 -0700885 }
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700886 }
887
888 @Override
889 public void event(NetworkConfigEvent event) {
890
891 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
892 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
Jonathan Hart092dfb22015-11-16 23:05:21 -0800893 event.configClass().equals(AaaConfig.class)) {
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700894
Jonathan Hart092dfb22015-11-16 23:05:21 -0800895 AaaConfig cfg = netCfgService.getConfig(appId, AaaConfig.class);
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700896 reconfigureNetwork(cfg);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100897
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400898 log.info("Reconfigured: {}", cfg.toString());
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700899 }
900 }
901 }
Amit Ghoshf739be52017-09-21 15:49:37 +0100902
903 private class InternalDeviceListener implements DeviceListener {
904 @Override
905 public void event(DeviceEvent event) {
906
907 switch (event.type()) {
908 case PORT_REMOVED:
909 DeviceId devId = event.subject().id();
910 PortNumber portNumber = event.port().number();
911 String sessionId = devId.toString() + portNumber.toString();
912
913 Map<String, StateMachine> sessionIdMap = StateMachine.sessionIdMap();
914 StateMachine removed = sessionIdMap.remove(sessionId);
915 if (removed != null) {
916 StateMachine.deleteStateMachineMapping(removed);
917 }
918
919 break;
920 default:
921 return;
922 }
923 }
924 }
kartikey dubeye1545422019-05-22 12:53:45 +0000925 private class AuthenticationStatisticsEventPublisher implements Runnable {
926 private final Logger log = getLogger(getClass());
927 public void run() {
928 log.info("Notifying AuthenticationStatisticsEvent");
929 aaaStatisticsManager.calculatePacketRoundtripTime();
930 log.debug("AcceptResponsesRx---" + aaaStatisticsManager.getAaaStats().getAcceptResponsesRx());
931 log.debug("AccessRequestsTx---" + aaaStatisticsManager.getAaaStats().getAccessRequestsTx());
932 log.debug("ChallengeResponsesRx---" + aaaStatisticsManager.getAaaStats().getChallengeResponsesRx());
933 log.debug("DroppedResponsesRx---" + aaaStatisticsManager.getAaaStats().getDroppedResponsesRx());
934 log.debug("InvalidValidatorsRx---" + aaaStatisticsManager.getAaaStats().getInvalidValidatorsRx());
935 log.debug("MalformedResponsesRx---" + aaaStatisticsManager.getAaaStats().getMalformedResponsesRx());
936 log.debug("PendingRequests---" + aaaStatisticsManager.getAaaStats().getPendingRequests());
937 log.debug("RejectResponsesRx---" + aaaStatisticsManager.getAaaStats().getRejectResponsesRx());
938 log.debug("RequestReTx---" + aaaStatisticsManager.getAaaStats().getRequestReTx());
939 log.debug("RequestRttMilis---" + aaaStatisticsManager.getAaaStats().getRequestRttMilis());
940 log.debug("UnknownServerRx---" + aaaStatisticsManager.getAaaStats().getUnknownServerRx());
941 log.debug("UnknownTypeRx---" + aaaStatisticsManager.getAaaStats().getUnknownTypeRx());
Shubham Sharma1e43c562019-06-19 14:18:12 +0000942 log.debug("TimedOutPackets----" + aaaStatisticsManager.getAaaStats().getTimedOutPackets());
Shubham Sharma1f193582019-07-11 12:12:41 +0000943 log.debug("EapolLogoffRx---" + aaaStatisticsManager.getAaaStats().getEapolLogoffRx());
944 log.debug("EapolAuthSuccessTrans---" + aaaStatisticsManager.getAaaStats().getEapolAuthSuccessTrans());
945 log.debug("EapolAuthFailureTrans---" +
946 aaaStatisticsManager.getAaaStats().getEapolAuthFailureTrans());
947 log.debug("EapolStartReqTrans---" +
948 aaaStatisticsManager.getAaaStats().getEapolStartReqTrans());
949 log.debug("EapolTransRespNotNak---" +
950 aaaStatisticsManager.getAaaStats().getEapolTransRespNotNak());
951 log.debug("EapPktTxauthChooseEap---" +
952 aaaStatisticsManager.getAaaStats().getEapPktTxauthChooseEap());
953 log.debug("EapolResIdentityMsgTrans---" +
954 aaaStatisticsManager.getAaaStats().getEapolResIdentityMsgTrans());
Shubham Sharma3c8c7022019-09-13 10:39:47 +0000955 log.debug("EapolFramesTx---" + aaaStatisticsManager.getAaaStats().getEapolFramesTx());
956 log.debug("AuthStateIdle---" + aaaStatisticsManager.getAaaStats().getAuthStateIdle());
957 log.debug("RequestIdFramesTx---" + aaaStatisticsManager.getAaaStats().getRequestIdFramesTx());
958 log.debug("ReqEapFramesTx---" + aaaStatisticsManager.getAaaStats().getReqEapFramesTx());
959 log.debug("InvalidPktType---" + aaaStatisticsManager.getAaaStats().getInvalidPktType());
960 log.debug("InvalidBodyLength---" + aaaStatisticsManager.getAaaStats().getInvalidBodyLength());
961 log.debug("ValidEapolFramesRx---" + aaaStatisticsManager.getAaaStats().getValidEapolFramesRx());
962 log.debug("PendingResSupp---" + aaaStatisticsManager.getAaaStats().getPendingResSupp());
963 log.debug("ResIdEapFramesRx---" + aaaStatisticsManager.getAaaStats().getEapolattrIdentity());
kartikey dubeye1545422019-05-22 12:53:45 +0000964 aaaStatisticsManager.getStatsDelegate().
965 notify(new AuthenticationStatisticsEvent(AuthenticationStatisticsEvent.Type.STATS_UPDATE,
966 aaaStatisticsManager.getAaaStats()));
967 }
Shubham Sharma4900ce62019-06-19 14:18:50 +0000968 }
969
970 private class ServerStatusChecker implements Runnable {
971 @Override
972 public void run() {
973 log.info("Notifying RadiusOperationalStatusEvent");
974 radiusOperationalStatusService.checkServerOperationalStatus();
975 log.info("--POSTING--" + radiusOperationalStatusService.getRadiusServerOperationalStatus());
976 radiusOperationalStatusService.getRadiusOprStDelegate()
977 .notify(new RadiusOperationalStatusEvent(
978 RadiusOperationalStatusEvent.Type.RADIUS_OPERATIONAL_STATUS,
979 radiusOperationalStatusService.
980 getRadiusServerOperationalStatus()));
kartikey dubeye1545422019-05-22 12:53:45 +0000981 }
Shubham Sharma4900ce62019-06-19 14:18:50 +0000982
983 }
984}