blob: b6b417d85b3ff626d63bad59befc177c081ada1b [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 */
alshabib6d527452016-06-01 18:00:47 -070016package org.opencord.aaa;
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;
22import java.nio.ByteBuffer;
23import java.util.Map;
24
Jonathan Hart932bedc2018-07-12 13:46:09 -070025import org.apache.commons.lang3.builder.ToStringBuilder;
Ari Saha89831742015-06-26 10:31:48 -070026import org.apache.felix.scr.annotations.Component;
27import org.apache.felix.scr.annotations.Deactivate;
Ari Saha89831742015-06-26 10:31:48 -070028import org.apache.felix.scr.annotations.Reference;
29import org.apache.felix.scr.annotations.ReferenceCardinality;
Jonathan Hart5db44532018-07-12 18:13:54 -070030import org.apache.felix.scr.annotations.Service;
Jonathan Hart4731dd92018-05-02 17:30:05 -070031import org.onlab.packet.DeserializationException;
Jonathan Harta46dddf2015-06-30 15:31:20 -070032import org.onlab.packet.EAP;
33import org.onlab.packet.EAPOL;
34import org.onlab.packet.EthType;
Ari Saha89831742015-06-26 10:31:48 -070035import org.onlab.packet.Ethernet;
Ari Saha89831742015-06-26 10:31:48 -070036import org.onlab.packet.MacAddress;
Jonathan Harta46dddf2015-06-30 15:31:20 -070037import org.onlab.packet.RADIUS;
38import org.onlab.packet.RADIUSAttribute;
Ari Saha89831742015-06-26 10:31:48 -070039import org.onosproject.core.ApplicationId;
40import org.onosproject.core.CoreService;
Jonathan Hart5db44532018-07-12 18:13:54 -070041import org.onosproject.event.AbstractListenerManager;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010042import org.onosproject.mastership.MastershipService;
Ari Saha89831742015-06-26 10:31:48 -070043import org.onosproject.net.ConnectPoint;
44import org.onosproject.net.DeviceId;
Ari Saha89831742015-06-26 10:31:48 -070045import org.onosproject.net.PortNumber;
Ray Milkeyfcb623d2015-10-01 16:48:18 -070046import org.onosproject.net.config.ConfigFactory;
47import org.onosproject.net.config.NetworkConfigEvent;
48import org.onosproject.net.config.NetworkConfigListener;
49import org.onosproject.net.config.NetworkConfigRegistry;
Amit Ghoshf739be52017-09-21 15:49:37 +010050import org.onosproject.net.device.DeviceEvent;
51import org.onosproject.net.device.DeviceListener;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010052import org.onosproject.net.device.DeviceService;
Ari Saha89831742015-06-26 10:31:48 -070053import org.onosproject.net.flow.DefaultTrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070054import org.onosproject.net.flow.TrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070055import org.onosproject.net.packet.DefaultOutboundPacket;
56import org.onosproject.net.packet.InboundPacket;
57import org.onosproject.net.packet.OutboundPacket;
58import org.onosproject.net.packet.PacketContext;
Ari Saha89831742015-06-26 10:31:48 -070059import org.onosproject.net.packet.PacketProcessor;
60import org.onosproject.net.packet.PacketService;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010061import org.opencord.sadis.SubscriberAndDeviceInformationService;
Deepa Vaddireddye0e10722017-09-27 05:00:10 +053062import org.osgi.service.component.annotations.Activate;
Ari Saha89831742015-06-26 10:31:48 -070063import org.slf4j.Logger;
64
Ari Saha89831742015-06-26 10:31:48 -070065/**
Jonathan Harta46dddf2015-06-30 15:31:20 -070066 * AAA application for ONOS.
Ari Saha89831742015-06-26 10:31:48 -070067 */
Jonathan Hart5db44532018-07-12 18:13:54 -070068@Service
Ari Saha89831742015-06-26 10:31:48 -070069@Component(immediate = true)
Jonathan Hart5db44532018-07-12 18:13:54 -070070public class AaaManager
71 extends AbstractListenerManager<AuthenticationEvent, AuthenticationEventListener>
72 implements AuthenticationService {
73
Charles Chandf7ff862017-01-20 11:22:05 -080074 private static final String APP_NAME = "org.opencord.aaa";
Ray Milkeyf51eba22015-09-25 10:24:23 -070075
Ray Milkeyf61a24e2015-09-24 16:34:02 -070076 private final Logger log = getLogger(getClass());
Ray Milkeyf51eba22015-09-25 10:24:23 -070077
Ray Milkeyf61a24e2015-09-24 16:34:02 -070078 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected CoreService coreService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070080
Ray Milkeyf61a24e2015-09-24 16:34:02 -070081 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected PacketService packetService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070083
Ray Milkeyf61a24e2015-09-24 16:34:02 -070084 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkeyfcb623d2015-10-01 16:48:18 -070085 protected NetworkConfigRegistry netCfgService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070086
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010087 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected DeviceService deviceService;
89
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 protected SubscriberAndDeviceInformationService subsService;
92
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected MastershipService mastershipService;
95
Amit Ghoshf739be52017-09-21 15:49:37 +010096 private final DeviceListener deviceListener = new InternalDeviceListener();
97
Ray Milkeyfcb623d2015-10-01 16:48:18 -070098 // NAS IP address
99 protected InetAddress nasIpAddress;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100100
101 // self MAC address
Jonathan Hart5db44532018-07-12 18:13:54 -0700102 protected String nasMacAddress;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100103
104 // Parsed RADIUS server addresses
105 protected InetAddress radiusIpAddress;
106
107 // MAC address of RADIUS server or net hop router
108 protected String radiusMacAddress;
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700109
110 // RADIUS server secret
111 protected String radiusSecret;
112
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100113 // bindings
114 protected CustomizationInfo customInfo;
Ray Milkey5d99bd12015-10-06 15:41:30 -0700115
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700116 // our application-specific event handler
117 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
Ray Milkeyf51eba22015-09-25 10:24:23 -0700118
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700119 // our unique identifier
120 private ApplicationId appId;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700121
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100122 // Setup specific customization/attributes on the RADIUS packets
123 PacketCustomizer pktCustomizer;
Ray Milkey967776a2015-10-07 14:37:17 -0700124
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100125 // packet customizer to use
126 private String customizer;
127
128 // Type of connection to use to communicate with Radius server, options are
129 // "socket" or "packet_out"
130 private String radiusConnectionType;
131
Jonathan Hart5db44532018-07-12 18:13:54 -0700132 // Object for the specific type of communication with the RADIUS
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100133 // server, socket based or packet_out based
134 RadiusCommunicator impl = null;
135
136 // latest configuration
137 AaaConfig newCfg;
Ray Milkey967776a2015-10-07 14:37:17 -0700138
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700139 // Configuration properties factory
140 private final ConfigFactory factory =
Jonathan Hart092dfb22015-11-16 23:05:21 -0800141 new ConfigFactory<ApplicationId, AaaConfig>(APP_SUBJECT_FACTORY,
142 AaaConfig.class,
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700143 "AAA") {
144 @Override
Jonathan Hart092dfb22015-11-16 23:05:21 -0800145 public AaaConfig createConfig() {
146 return new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700147 }
148 };
Ray Milkeyf51eba22015-09-25 10:24:23 -0700149
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700150 // Listener for config changes
151 private final InternalConfigListener cfgListener = new InternalConfigListener();
Ari Saha89831742015-06-26 10:31:48 -0700152
Jonathan Hart5db44532018-07-12 18:13:54 -0700153 private StateMachineDelegate delegate = new InternalStateMachineDelegate();
154
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700155 /**
156 * Builds an EAPOL packet based on the given parameters.
157 *
158 * @param dstMac destination MAC address
159 * @param srcMac source MAC address
160 * @param vlan vlan identifier
161 * @param eapolType EAPOL type
162 * @param eap EAP payload
163 * @return Ethernet frame
164 */
165 private static Ethernet buildEapolResponse(MacAddress dstMac, MacAddress srcMac,
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100166 short vlan, byte eapolType, EAP eap, byte priorityCode) {
Ari Saha89831742015-06-26 10:31:48 -0700167
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700168 Ethernet eth = new Ethernet();
169 eth.setDestinationMACAddress(dstMac.toBytes());
170 eth.setSourceMACAddress(srcMac.toBytes());
171 eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
172 if (vlan != Ethernet.VLAN_UNTAGGED) {
173 eth.setVlanID(vlan);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100174 eth.setPriorityCode(priorityCode);
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700175 }
176 //eapol header
177 EAPOL eapol = new EAPOL();
178 eapol.setEapolType(eapolType);
179 eapol.setPacketLength(eap.getLength());
Ari Saha89831742015-06-26 10:31:48 -0700180
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700181 //eap part
182 eapol.setPayload(eap);
183
184 eth.setPayload(eapol);
185 eth.setPad(true);
186 return eth;
187 }
Ari Saha89831742015-06-26 10:31:48 -0700188
Ari Saha89831742015-06-26 10:31:48 -0700189 @Activate
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700190 public void activate() {
Charles Chandf7ff862017-01-20 11:22:05 -0800191 appId = coreService.registerApplication(APP_NAME);
Jonathan Hart5db44532018-07-12 18:13:54 -0700192 eventDispatcher.addSink(AuthenticationEvent.class, listenerRegistry);
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400193 netCfgService.addListener(cfgListener);
194 netCfgService.registerConfigFactory(factory);
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530195 customInfo = new CustomizationInfo(subsService, deviceService);
Jonathan Hart092dfb22015-11-16 23:05:21 -0800196 cfgListener.reconfigureNetwork(netCfgService.getConfig(appId, AaaConfig.class));
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400197 log.info("Starting with config {} {}", this, newCfg);
198
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530199 configureRadiusCommunication();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700200
Ari Saha89831742015-06-26 10:31:48 -0700201 // register our event handler
Brian O'Connord9c7da02015-07-29 17:49:24 -0700202 packetService.addProcessor(processor, PacketProcessor.director(2));
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100203
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700204
205 StateMachine.initializeMaps();
Jonathan Hart5db44532018-07-12 18:13:54 -0700206 StateMachine.setDelegate(delegate);
Ari Saha89831742015-06-26 10:31:48 -0700207
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100208 impl.initializeLocalState(newCfg);
alshabib27afc1d2016-12-23 00:33:58 -0800209
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100210 impl.requestIntercepts();
211
Amit Ghoshf739be52017-09-21 15:49:37 +0100212 deviceService.addListener(deviceListener);
213
Jian Li13c67162015-12-09 13:20:34 -0800214 log.info("Started");
Ari Saha89831742015-06-26 10:31:48 -0700215 }
216
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530217
Ari Saha89831742015-06-26 10:31:48 -0700218 @Deactivate
219 public void deactivate() {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100220 impl.withdrawIntercepts();
Ari Saha89831742015-06-26 10:31:48 -0700221 packetService.removeProcessor(processor);
Deepa Vaddireddyb9c24c62017-09-21 13:45:30 +0530222 netCfgService.removeListener(cfgListener);
Jonathan Hart5db44532018-07-12 18:13:54 -0700223 StateMachine.unsetDelegate(delegate);
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530224 StateMachine.destroyMaps();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100225 impl.deactivate();
Amit Ghoshf739be52017-09-21 15:49:37 +0100226 deviceService.removeListener(deviceListener);
Jonathan Hart5db44532018-07-12 18:13:54 -0700227 eventDispatcher.removeSink(AuthenticationEvent.class);
Jian Li13c67162015-12-09 13:20:34 -0800228 log.info("Stopped");
Ray Milkey967776a2015-10-07 14:37:17 -0700229 }
230
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530231 private void configureRadiusCommunication() {
232 if (radiusConnectionType.toLowerCase().equals("socket")) {
233 impl = new SocketBasedRadiusCommunicator(appId, packetService, this);
234 } else {
235 impl = new PortBasedRadiusCommunicator(appId, packetService, mastershipService,
236 deviceService, subsService, pktCustomizer, this);
237 }
238 }
239
240 private void configurePacketCustomizer() {
241 switch (customizer.toLowerCase()) {
242 case "sample":
243 pktCustomizer = new SamplePacketCustomizer(customInfo);
244 log.info("Created SamplePacketCustomizer");
245 break;
Saurav Dase72358a2018-11-13 21:56:46 -0800246 case "att":
247 pktCustomizer = new AttPacketCustomizer(customInfo);
248 log.info("Created AttPacketCustomizer");
249 break;
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530250 default:
251 pktCustomizer = new PacketCustomizer(customInfo);
252 log.info("Created default PacketCustomizer");
253 break;
254 }
255 }
256
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100257 /**
258 * Send RADIUS packet to the RADIUS server.
259 *
260 * @param radiusPacket RADIUS packet to be sent to server.
261 * @param inPkt Incoming EAPOL packet
262 */
263 protected void sendRadiusPacket(RADIUS radiusPacket, InboundPacket inPkt) {
264 impl.sendRadiusPacket(radiusPacket, inPkt);
265 }
Ray Milkey967776a2015-10-07 14:37:17 -0700266
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100267 /**
268 * Handles RADIUS packets.
269 *
270 * @param radiusPacket RADIUS packet coming from the RADIUS server.
271 * @throws StateMachineException if an illegal state transition is triggered
Jonathan Hart4731dd92018-05-02 17:30:05 -0700272 * @throws DeserializationException if packet deserialization fails
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100273 */
Jonathan Hart4731dd92018-05-02 17:30:05 -0700274 public void handleRadiusPacket(RADIUS radiusPacket)
275 throws StateMachineException, DeserializationException {
Saurav Das987441a2018-09-18 16:33:47 -0700276 if (log.isTraceEnabled()) {
277 log.trace("Received RADIUS packet {}", radiusPacket);
278 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100279 StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier());
280 if (stateMachine == null) {
Saurav Das987441a2018-09-18 16:33:47 -0700281 log.error("Invalid packet identifier {}, could not find corresponding "
282 + "state machine ... exiting", radiusPacket.getIdentifier());
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100283 return;
Ray Milkey967776a2015-10-07 14:37:17 -0700284 }
Ari Saha89831742015-06-26 10:31:48 -0700285
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100286 EAP eapPayload;
287 Ethernet eth;
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700288
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100289 switch (radiusPacket.getCode()) {
290 case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400291 log.debug("RADIUS packet: RADIUS_CODE_ACCESS_CHALLENGE");
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100292 RADIUSAttribute radiusAttrState = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE);
293 byte[] challengeState = null;
294 if (radiusAttrState != null) {
295 challengeState = radiusAttrState.getValue();
296 }
297 eapPayload = radiusPacket.decapsulateMessage();
298 stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState);
299 eth = buildEapolResponse(stateMachine.supplicantAddress(),
300 MacAddress.valueOf(nasMacAddress),
301 stateMachine.vlanId(),
302 EAPOL.EAPOL_PACKET,
303 eapPayload, stateMachine.priorityCode());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400304 log.debug("Send EAP challenge response to supplicant {}", stateMachine.supplicantAddress().toString());
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100305 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
306 break;
307 case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400308 log.debug("RADIUS packet: RADIUS_CODE_ACCESS_ACCEPT");
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100309 //send an EAPOL - Success to the supplicant.
310 byte[] eapMessageSuccess =
311 radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
Jonathan Hart4731dd92018-05-02 17:30:05 -0700312 eapPayload = EAP.deserializer().deserialize(
313 eapMessageSuccess, 0, eapMessageSuccess.length);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100314 eth = buildEapolResponse(stateMachine.supplicantAddress(),
315 MacAddress.valueOf(nasMacAddress),
316 stateMachine.vlanId(),
317 EAPOL.EAPOL_PACKET,
318 eapPayload, stateMachine.priorityCode());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400319 log.info("Send EAP success message to supplicant {}", stateMachine.supplicantAddress().toString());
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100320 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
321
322 stateMachine.authorizeAccess();
323
324 break;
325 case RADIUS.RADIUS_CODE_ACCESS_REJECT:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400326 log.debug("RADIUS packet: RADIUS_CODE_ACCESS_REJECT");
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100327 //send an EAPOL - Failure to the supplicant.
328 byte[] eapMessageFailure;
329 eapPayload = new EAP();
330 RADIUSAttribute radiusAttrEap = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE);
331 if (radiusAttrEap == null) {
332 eapPayload.setCode(EAP.FAILURE);
333 eapPayload.setIdentifier(stateMachine.challengeIdentifier());
334 eapPayload.setLength(EAP.EAP_HDR_LEN_SUC_FAIL);
335 } else {
336 eapMessageFailure = radiusAttrEap.getValue();
Jonathan Hart4731dd92018-05-02 17:30:05 -0700337 eapPayload = EAP.deserializer().deserialize(
338 eapMessageFailure, 0, eapMessageFailure.length);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100339 }
340 eth = buildEapolResponse(stateMachine.supplicantAddress(),
341 MacAddress.valueOf(nasMacAddress),
342 stateMachine.vlanId(),
343 EAPOL.EAPOL_PACKET,
344 eapPayload, stateMachine.priorityCode());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400345 log.warn("Send EAP failure message to supplicant {}", stateMachine.supplicantAddress().toString());
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100346 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
347 stateMachine.denyAccess();
348
349 break;
350 default:
351 log.warn("Unknown RADIUS message received with code: {}", radiusPacket.getCode());
352 }
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700353 }
354
Ray Milkey967776a2015-10-07 14:37:17 -0700355 /**
356 * Send the ethernet packet to the supplicant.
357 *
358 * @param ethernetPkt the ethernet packet
359 * @param connectPoint the connect point to send out
360 */
361 private void sendPacketToSupplicant(Ethernet ethernetPkt, ConnectPoint connectPoint) {
362 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
363 OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(),
364 treatment, ByteBuffer.wrap(ethernetPkt.serialize()));
Saurav Das987441a2018-09-18 16:33:47 -0700365 if (log.isTraceEnabled()) {
366 EAPOL eap = ((EAPOL) ethernetPkt.getPayload());
367 log.trace("Sending eapol payload {} enclosed in {} to supplicant at {}",
368 eap, ethernetPkt, connectPoint);
369 }
Ray Milkey967776a2015-10-07 14:37:17 -0700370 packetService.emit(packet);
371 }
372
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400373 @Override
374 public String toString() {
375 return ToStringBuilder.reflectionToString(this);
376 }
377
Ari Saha89831742015-06-26 10:31:48 -0700378 // our handler defined as a private inner class
379
380 /**
381 * Packet processor responsible for forwarding packets along their paths.
382 */
383 private class ReactivePacketProcessor implements PacketProcessor {
384 @Override
385 public void process(PacketContext context) {
386
387 // Extract the original Ethernet frame from the packet information
388 InboundPacket pkt = context.inPacket();
389 Ethernet ethPkt = pkt.parsed();
390 if (ethPkt == null) {
391 return;
392 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100393
Ray Milkeyf51eba22015-09-25 10:24:23 -0700394 try {
395 // identify if incoming packet comes from supplicant (EAP) or RADIUS
396 switch (EthType.EtherType.lookup(ethPkt.getEtherType())) {
397 case EAPOL:
398 handleSupplicantPacket(context.inPacket());
399 break;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700400 default:
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100401 // any other packets let the specific implementation handle
402 impl.handlePacketFromServer(context);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700403 }
Ray Milkey967776a2015-10-07 14:37:17 -0700404 } catch (StateMachineException e) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100405 log.warn("Unable to process packet:", e);
Ari Saha89831742015-06-26 10:31:48 -0700406 }
407 }
408
Ray Milkey9eb293f2015-09-30 15:09:17 -0700409 /**
410 * Creates and initializes common fields of a RADIUS packet.
411 *
Ray Milkey967776a2015-10-07 14:37:17 -0700412 * @param stateMachine state machine for the request
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700413 * @param eapPacket EAP packet
Ray Milkey9eb293f2015-09-30 15:09:17 -0700414 * @return RADIUS packet
415 */
Ray Milkey967776a2015-10-07 14:37:17 -0700416 private RADIUS getRadiusPayload(StateMachine stateMachine, byte identifier, EAP eapPacket) {
Ray Milkey9eb293f2015-09-30 15:09:17 -0700417 RADIUS radiusPayload =
418 new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
419 eapPacket.getIdentifier());
Ray Milkey967776a2015-10-07 14:37:17 -0700420
421 // set Request Authenticator in StateMachine
422 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
423
Ray Milkey9eb293f2015-09-30 15:09:17 -0700424 radiusPayload.setIdentifier(identifier);
425 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
Ray Milkey967776a2015-10-07 14:37:17 -0700426 stateMachine.username());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700427
428 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
Jonathan Hart092dfb22015-11-16 23:05:21 -0800429 AaaManager.this.nasIpAddress.getAddress());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700430
431 radiusPayload.encapsulateMessage(eapPacket);
Ray Milkey9eb293f2015-09-30 15:09:17 -0700432
433 return radiusPayload;
434 }
Ari Saha89831742015-06-26 10:31:48 -0700435
436 /**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700437 * Handles PAE packets (supplicant).
438 *
439 * @param inPacket Ethernet packet coming from the supplicant
Ari Saha89831742015-06-26 10:31:48 -0700440 */
Ray Milkeyf51eba22015-09-25 10:24:23 -0700441 private void handleSupplicantPacket(InboundPacket inPacket) throws StateMachineException {
Jonathan Harta46dddf2015-06-30 15:31:20 -0700442 Ethernet ethPkt = inPacket.parsed();
Ari Saha89831742015-06-26 10:31:48 -0700443 // Where does it come from?
Jonathan Hart092dfb22015-11-16 23:05:21 -0800444 MacAddress srcMac = ethPkt.getSourceMAC();
Ari Saha89831742015-06-26 10:31:48 -0700445
Jonathan Harta46dddf2015-06-30 15:31:20 -0700446 DeviceId deviceId = inPacket.receivedFrom().deviceId();
447 PortNumber portNumber = inPacket.receivedFrom().port();
Ari Saha89831742015-06-26 10:31:48 -0700448 String sessionId = deviceId.toString() + portNumber.toString();
Saurav Das987441a2018-09-18 16:33:47 -0700449 EAPOL eapol = (EAPOL) ethPkt.getPayload();
450 if (log.isTraceEnabled()) {
451 log.trace("Received EAPOL packet {} in enclosing packet {} from "
452 + "dev/port: {}/{}", eapol, ethPkt, deviceId,
453 portNumber);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100454 }
Jonathan Harta46dddf2015-06-30 15:31:20 -0700455
Saurav Das987441a2018-09-18 16:33:47 -0700456 StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
457 if (stateMachine == null) {
458 log.debug("Creating new state machine for sessionId: {} for "
459 + "dev/port: {}/{}", sessionId, deviceId, portNumber);
460 stateMachine = new StateMachine(sessionId);
461 } else {
462 log.debug("Using existing state-machine for sessionId: {}", sessionId);
463 }
464
Ari Saha89831742015-06-26 10:31:48 -0700465
466 switch (eapol.getEapolType()) {
467 case EAPOL.EAPOL_START:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400468 log.debug("EAP packet: EAPOL_START");
Ray Milkeyf51eba22015-09-25 10:24:23 -0700469 stateMachine.setSupplicantConnectpoint(inPacket.receivedFrom());
Jonathan Hart5db44532018-07-12 18:13:54 -0700470 stateMachine.start();
Ari Saha89831742015-06-26 10:31:48 -0700471
Ray Milkeyf51eba22015-09-25 10:24:23 -0700472 //send an EAP Request/Identify to the supplicant
473 EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.identifier(), EAP.ATTR_IDENTITY, null);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100474 if (ethPkt.getVlanID() != Ethernet.VLAN_UNTAGGED) {
475 stateMachine.setPriorityCode(ethPkt.getPriorityCode());
476 }
Jonathan Hart092dfb22015-11-16 23:05:21 -0800477 Ethernet eth = buildEapolResponse(srcMac, MacAddress.valueOf(nasMacAddress),
Ray Milkeyf51eba22015-09-25 10:24:23 -0700478 ethPkt.getVlanID(), EAPOL.EAPOL_PACKET,
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100479 eapPayload, stateMachine.priorityCode());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400480
Jonathan Hart092dfb22015-11-16 23:05:21 -0800481 stateMachine.setSupplicantAddress(srcMac);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700482 stateMachine.setVlanId(ethPkt.getVlanID());
Ari Saha89831742015-06-26 10:31:48 -0700483
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400484 log.debug("Getting EAP identity from supplicant {}", stateMachine.supplicantAddress().toString());
Ray Milkey967776a2015-10-07 14:37:17 -0700485 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
Ari Saha89831742015-06-26 10:31:48 -0700486
487 break;
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800488 case EAPOL.EAPOL_LOGOFF:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400489 log.debug("EAP packet: EAPOL_LOGOFF");
Ray Milkeyb34b4962016-01-04 10:24:43 -0800490 if (stateMachine.state() == StateMachine.STATE_AUTHORIZED) {
491 stateMachine.logoff();
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800492 }
493
494 break;
Ari Saha89831742015-06-26 10:31:48 -0700495 case EAPOL.EAPOL_PACKET:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700496 RADIUS radiusPayload;
Ray Milkey9eb293f2015-09-30 15:09:17 -0700497 // check if this is a Response/Identify or a Response/TLS
Ari Saha89831742015-06-26 10:31:48 -0700498 EAP eapPacket = (EAP) eapol.getPayload();
499
500 byte dataType = eapPacket.getDataType();
501 switch (dataType) {
Ari Saha89831742015-06-26 10:31:48 -0700502
Ray Milkey9eb293f2015-09-30 15:09:17 -0700503 case EAP.ATTR_IDENTITY:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400504 log.debug("EAP packet: EAPOL_PACKET ATTR_IDENTITY");
Ray Milkey9eb293f2015-09-30 15:09:17 -0700505 // request id access to RADIUS
506 stateMachine.setUsername(eapPacket.getData());
Ari Saha89831742015-06-26 10:31:48 -0700507
Ray Milkey967776a2015-10-07 14:37:17 -0700508 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100509 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Jonathan Hart092dfb22015-11-16 23:05:21 -0800510 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Ari Saha89831742015-06-26 10:31:48 -0700511
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100512 sendRadiusPacket(radiusPayload, inPacket);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700513
Ray Milkey9eb293f2015-09-30 15:09:17 -0700514 // change the state to "PENDING"
515 stateMachine.requestAccess();
516 break;
Ari Saha89831742015-06-26 10:31:48 -0700517 case EAP.ATTR_MD5:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400518 log.debug("EAP packet: EAPOL_PACKET ATTR_MD5");
Ray Milkey9eb293f2015-09-30 15:09:17 -0700519 // verify if the EAP identifier corresponds to the
520 // challenge identifier from the client state
521 // machine.
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700522 if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) {
Ari Saha89831742015-06-26 10:31:48 -0700523 //send the RADIUS challenge response
Ray Milkey967776a2015-10-07 14:37:17 -0700524 radiusPayload =
525 getRadiusPayload(stateMachine,
526 stateMachine.identifier(),
527 eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100528 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700529
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800530 if (stateMachine.challengeState() != null) {
531 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
532 stateMachine.challengeState());
533 }
Jonathan Hart092dfb22015-11-16 23:05:21 -0800534 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100535 sendRadiusPacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700536 }
537 break;
538 case EAP.ATTR_TLS:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400539 log.debug("EAP packet: EAPOL_PACKET ATTR_TLS");
Ray Milkey9eb293f2015-09-30 15:09:17 -0700540 // request id access to RADIUS
Ray Milkey967776a2015-10-07 14:37:17 -0700541 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100542 radiusPayload = pktCustomizer.customizePacket(radiusPayload, inPacket);
Ari Saha89831742015-06-26 10:31:48 -0700543
Qianqian Hub55a1ac2015-12-23 20:44:48 +0800544 if (stateMachine.challengeState() != null) {
545 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
546 stateMachine.challengeState());
547 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700548 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
Ari Saha89831742015-06-26 10:31:48 -0700549
Jonathan Hart092dfb22015-11-16 23:05:21 -0800550 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100551 sendRadiusPacket(radiusPayload, inPacket);
Ray Milkey5493b512015-10-21 12:13:49 -0700552
Ray Milkeyf3790b82015-10-21 16:28:08 -0700553 if (stateMachine.state() != StateMachine.STATE_PENDING) {
554 stateMachine.requestAccess();
555 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700556
Ari Saha89831742015-06-26 10:31:48 -0700557 break;
558 default:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400559 log.warn("Unknown EAP packet type");
Ari Saha89831742015-06-26 10:31:48 -0700560 return;
561 }
562 break;
563 default:
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400564 log.debug("Skipping EAPOL message {}", eapol.getEapolType());
Ari Saha89831742015-06-26 10:31:48 -0700565 }
566 }
Ray Milkey967776a2015-10-07 14:37:17 -0700567 }
568
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100569 /**
Jonathan Hart5db44532018-07-12 18:13:54 -0700570 * Delegate allowing the StateMachine to notify us of events.
571 */
572 private class InternalStateMachineDelegate implements StateMachineDelegate {
573
574 @Override
575 public void notify(AuthenticationEvent authenticationEvent) {
576 log.info("Auth event {} for {}",
577 authenticationEvent.type(), authenticationEvent.subject());
578 post(authenticationEvent);
579 }
580 }
581
582 /**
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100583 * Configuration Listener, handles change in configuration.
584 */
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700585 private class InternalConfigListener implements NetworkConfigListener {
586
587 /**
Ray Milkeyc9e8dcc2015-12-30 10:31:32 -0800588 * Reconfigures the AAA application according to the
589 * configuration parameters passed.
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700590 *
591 * @param cfg configuration object
592 */
Jonathan Hart092dfb22015-11-16 23:05:21 -0800593 private void reconfigureNetwork(AaaConfig cfg) {
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400594 log.info("Reconfiguring AaaConfig from config: {}", cfg);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100595
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700596 if (cfg == null) {
Jonathan Hart092dfb22015-11-16 23:05:21 -0800597 newCfg = new AaaConfig();
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700598 } else {
599 newCfg = cfg;
600 }
601 if (newCfg.nasIp() != null) {
602 nasIpAddress = newCfg.nasIp();
603 }
604 if (newCfg.radiusIp() != null) {
605 radiusIpAddress = newCfg.radiusIp();
606 }
607 if (newCfg.radiusMac() != null) {
608 radiusMacAddress = newCfg.radiusMac();
609 }
610 if (newCfg.nasMac() != null) {
611 nasMacAddress = newCfg.nasMac();
612 }
613 if (newCfg.radiusSecret() != null) {
614 radiusSecret = newCfg.radiusSecret();
615 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100616
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530617 boolean reconfigureCustomizer = false;
618 if (customizer == null || !customizer.equals(newCfg.radiusPktCustomizer())) {
619 customizer = newCfg.radiusPktCustomizer();
620 configurePacketCustomizer();
621 reconfigureCustomizer = true;
622 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100623
Deepa Vaddireddye0e10722017-09-27 05:00:10 +0530624 if (radiusConnectionType == null
625 || reconfigureCustomizer
626 || !radiusConnectionType.equals(newCfg.radiusConnectionType())) {
627 radiusConnectionType = newCfg.radiusConnectionType();
628 if (impl != null) {
629 impl.withdrawIntercepts();
630 impl.clearLocalState();
631 }
632 configureRadiusCommunication();
633 impl.initializeLocalState(newCfg);
634 impl.requestIntercepts();
635 } else if (impl != null) {
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100636 impl.clearLocalState();
637 impl.initializeLocalState(newCfg);
Ray Milkey5d99bd12015-10-06 15:41:30 -0700638 }
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700639 }
640
641 @Override
642 public void event(NetworkConfigEvent event) {
643
644 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
645 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
Jonathan Hart092dfb22015-11-16 23:05:21 -0800646 event.configClass().equals(AaaConfig.class)) {
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700647
Jonathan Hart092dfb22015-11-16 23:05:21 -0800648 AaaConfig cfg = netCfgService.getConfig(appId, AaaConfig.class);
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700649 reconfigureNetwork(cfg);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100650
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400651 log.info("Reconfigured: {}", cfg.toString());
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700652 }
653 }
654 }
Amit Ghoshf739be52017-09-21 15:49:37 +0100655
656 private class InternalDeviceListener implements DeviceListener {
657 @Override
658 public void event(DeviceEvent event) {
659
660 switch (event.type()) {
661 case PORT_REMOVED:
662 DeviceId devId = event.subject().id();
663 PortNumber portNumber = event.port().number();
664 String sessionId = devId.toString() + portNumber.toString();
665
666 Map<String, StateMachine> sessionIdMap = StateMachine.sessionIdMap();
667 StateMachine removed = sessionIdMap.remove(sessionId);
668 if (removed != null) {
669 StateMachine.deleteStateMachineMapping(removed);
670 }
671
672 break;
673 default:
674 return;
675 }
676 }
677 }
Ari Saha89831742015-06-26 10:31:48 -0700678}