blob: 0339a7e9e65079ec2b7aef25dfcd1488655e797e [file] [log] [blame]
Ari Saha79d7c252015-06-26 10:31:48 -07001/*
2 * Copyright 2015 AT&T Foundry
3 *
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 */
16package org.onosproject.aaa;
17
Jonathan Hartb92cc512015-11-16 23:05:21 -080018import com.google.common.util.concurrent.ThreadFactoryBuilder;
Ari Saha79d7c252015-06-26 10:31:48 -070019import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
Ari Saha79d7c252015-06-26 10:31:48 -070022import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
Jonathan Hart4a60bb32015-06-30 15:31:20 -070024import org.onlab.packet.DeserializationException;
25import org.onlab.packet.EAP;
26import org.onlab.packet.EAPOL;
27import org.onlab.packet.EthType;
Ari Saha79d7c252015-06-26 10:31:48 -070028import org.onlab.packet.Ethernet;
Ari Saha79d7c252015-06-26 10:31:48 -070029import org.onlab.packet.MacAddress;
Jonathan Hart4a60bb32015-06-30 15:31:20 -070030import org.onlab.packet.RADIUS;
31import org.onlab.packet.RADIUSAttribute;
Ari Saha79d7c252015-06-26 10:31:48 -070032import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
34import org.onosproject.net.ConnectPoint;
35import org.onosproject.net.DeviceId;
Ari Saha79d7c252015-06-26 10:31:48 -070036import org.onosproject.net.PortNumber;
Ray Milkey57f2e142015-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;
Ari Saha79d7c252015-06-26 10:31:48 -070041import org.onosproject.net.flow.DefaultTrafficSelector;
42import org.onosproject.net.flow.DefaultTrafficTreatment;
Ari Saha79d7c252015-06-26 10:31:48 -070043import org.onosproject.net.flow.TrafficSelector;
44import org.onosproject.net.flow.TrafficTreatment;
Ari Saha79d7c252015-06-26 10:31:48 -070045import org.onosproject.net.packet.DefaultOutboundPacket;
46import org.onosproject.net.packet.InboundPacket;
47import org.onosproject.net.packet.OutboundPacket;
48import org.onosproject.net.packet.PacketContext;
Ari Saha79d7c252015-06-26 10:31:48 -070049import org.onosproject.net.packet.PacketProcessor;
50import org.onosproject.net.packet.PacketService;
Ari Saha79d7c252015-06-26 10:31:48 -070051import org.onosproject.xosintegration.VoltTenantService;
Ari Saha79d7c252015-06-26 10:31:48 -070052import org.slf4j.Logger;
53
Jonathan Hartb92cc512015-11-16 23:05:21 -080054import java.io.IOException;
55import java.net.DatagramPacket;
56import java.net.DatagramSocket;
57import java.net.InetAddress;
58import java.nio.ByteBuffer;
59import java.util.concurrent.ExecutorService;
60import java.util.concurrent.Executors;
Ray Milkey4ed93692015-10-07 14:37:17 -070061
Ray Milkey57f2e142015-10-01 16:48:18 -070062import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
Aaron Kruglikov07a923d2015-07-03 13:30:57 -070063import static org.onosproject.net.packet.PacketPriority.CONTROL;
Ari Saha79d7c252015-06-26 10:31:48 -070064import static org.slf4j.LoggerFactory.getLogger;
65
Ari Saha79d7c252015-06-26 10:31:48 -070066/**
Jonathan Hart4a60bb32015-06-30 15:31:20 -070067 * AAA application for ONOS.
Ari Saha79d7c252015-06-26 10:31:48 -070068 */
69@Component(immediate = true)
Jonathan Hartb92cc512015-11-16 23:05:21 -080070public class AaaManager {
Ray Milkey1c0ea1a2015-09-25 10:24:23 -070071
Ray Milkey75879ef2015-09-24 16:34:02 -070072 // for verbose output
73 private final Logger log = getLogger(getClass());
Ray Milkey1c0ea1a2015-09-25 10:24:23 -070074
Ray Milkey75879ef2015-09-24 16:34:02 -070075 // a list of our dependencies :
76 // to register with ONOS as an application - described next
77 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
78 protected CoreService coreService;
Ray Milkey1c0ea1a2015-09-25 10:24:23 -070079
Ray Milkey75879ef2015-09-24 16:34:02 -070080 // to receive Packet-in events that we'll respond to
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected PacketService packetService;
Ray Milkey1c0ea1a2015-09-25 10:24:23 -070083
Ray Milkey75879ef2015-09-24 16:34:02 -070084 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 protected VoltTenantService voltTenantService;
Ray Milkey1c0ea1a2015-09-25 10:24:23 -070086
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkey57f2e142015-10-01 16:48:18 -070088 protected NetworkConfigRegistry netCfgService;
Ray Milkey1c0ea1a2015-09-25 10:24:23 -070089
Ray Milkey57f2e142015-10-01 16:48:18 -070090 // Parsed RADIUS server addresses
91 protected InetAddress radiusIpAddress;
92 protected String radiusMacAddress;
93
94 // NAS IP address
95 protected InetAddress nasIpAddress;
96 protected String nasMacAddress;
97
98 // RADIUS server secret
99 protected String radiusSecret;
100
101 // ID of RADIUS switch
102 protected String radiusSwitch;
103
104 // RADIUS port number
105 protected long radiusPort;
Ray Milkey1c0ea1a2015-09-25 10:24:23 -0700106
Ray Milkeyaf86fbf2015-10-06 15:41:30 -0700107 // RADIUS server TCP port number
108 protected short radiusServerPort;
109
Ray Milkey75879ef2015-09-24 16:34:02 -0700110 // our application-specific event handler
111 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
Ray Milkey1c0ea1a2015-09-25 10:24:23 -0700112
Ray Milkey75879ef2015-09-24 16:34:02 -0700113 // our unique identifier
114 private ApplicationId appId;
Ray Milkey1c0ea1a2015-09-25 10:24:23 -0700115
Ray Milkey4ed93692015-10-07 14:37:17 -0700116 // Socket used for UDP communications with RADIUS server
117 private DatagramSocket radiusSocket;
118
119 // Executor for RADIUS communication thread
120 private ExecutorService executor;
121
Ray Milkey57f2e142015-10-01 16:48:18 -0700122 // Configuration properties factory
123 private final ConfigFactory factory =
Jonathan Hartb92cc512015-11-16 23:05:21 -0800124 new ConfigFactory<ApplicationId, AaaConfig>(APP_SUBJECT_FACTORY,
125 AaaConfig.class,
Ray Milkey57f2e142015-10-01 16:48:18 -0700126 "AAA") {
127 @Override
Jonathan Hartb92cc512015-11-16 23:05:21 -0800128 public AaaConfig createConfig() {
129 return new AaaConfig();
Ray Milkey57f2e142015-10-01 16:48:18 -0700130 }
131 };
Ray Milkey1c0ea1a2015-09-25 10:24:23 -0700132
Ray Milkey57f2e142015-10-01 16:48:18 -0700133 // Listener for config changes
134 private final InternalConfigListener cfgListener = new InternalConfigListener();
Ari Saha79d7c252015-06-26 10:31:48 -0700135
Ray Milkey75879ef2015-09-24 16:34:02 -0700136 /**
137 * Builds an EAPOL packet based on the given parameters.
138 *
139 * @param dstMac destination MAC address
140 * @param srcMac source MAC address
141 * @param vlan vlan identifier
142 * @param eapolType EAPOL type
143 * @param eap EAP payload
144 * @return Ethernet frame
145 */
146 private static Ethernet buildEapolResponse(MacAddress dstMac, MacAddress srcMac,
147 short vlan, byte eapolType, EAP eap) {
Ari Saha79d7c252015-06-26 10:31:48 -0700148
Ray Milkey75879ef2015-09-24 16:34:02 -0700149 Ethernet eth = new Ethernet();
150 eth.setDestinationMACAddress(dstMac.toBytes());
151 eth.setSourceMACAddress(srcMac.toBytes());
152 eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
153 if (vlan != Ethernet.VLAN_UNTAGGED) {
154 eth.setVlanID(vlan);
155 }
156 //eapol header
157 EAPOL eapol = new EAPOL();
158 eapol.setEapolType(eapolType);
159 eapol.setPacketLength(eap.getLength());
Ari Saha79d7c252015-06-26 10:31:48 -0700160
Ray Milkey75879ef2015-09-24 16:34:02 -0700161 //eap part
162 eapol.setPayload(eap);
163
164 eth.setPayload(eapol);
165 eth.setPad(true);
166 return eth;
167 }
Ari Saha79d7c252015-06-26 10:31:48 -0700168
Ari Saha79d7c252015-06-26 10:31:48 -0700169 @Activate
Ray Milkey57f2e142015-10-01 16:48:18 -0700170 public void activate() {
171 netCfgService.addListener(cfgListener);
172 netCfgService.registerConfigFactory(factory);
173
Ari Saha79d7c252015-06-26 10:31:48 -0700174 // "org.onosproject.aaa" is the FQDN of our app
175 appId = coreService.registerApplication("org.onosproject.aaa");
Ray Milkey57f2e142015-10-01 16:48:18 -0700176
Jonathan Hartb92cc512015-11-16 23:05:21 -0800177 cfgListener.reconfigureNetwork(netCfgService.getConfig(appId, AaaConfig.class));
Ray Milkey57f2e142015-10-01 16:48:18 -0700178
Ari Saha79d7c252015-06-26 10:31:48 -0700179 // register our event handler
Brian O'Connor3b783262015-07-29 17:49:24 -0700180 packetService.addProcessor(processor, PacketProcessor.director(2));
Aaron Kruglikov07a923d2015-07-03 13:30:57 -0700181 requestIntercepts();
Ray Milkey75879ef2015-09-24 16:34:02 -0700182
183 StateMachine.initializeMaps();
Ari Saha79d7c252015-06-26 10:31:48 -0700184
Ray Milkey4ed93692015-10-07 14:37:17 -0700185 try {
186 radiusSocket = new DatagramSocket(radiusServerPort);
187 } catch (Exception ex) {
188 log.error("Can't open RADIUS socket", ex);
189 }
190
191 executor = Executors.newSingleThreadExecutor(
192 new ThreadFactoryBuilder()
193 .setNameFormat("AAA-radius-%d").build());
194 executor.execute(radiusListener);
Jian Li02e5ed62015-12-09 13:20:34 -0800195 log.info("Started");
Ari Saha79d7c252015-06-26 10:31:48 -0700196 }
197
198 @Deactivate
199 public void deactivate() {
Aaron Kruglikov07a923d2015-07-03 13:30:57 -0700200 withdrawIntercepts();
Ari Saha79d7c252015-06-26 10:31:48 -0700201 // de-register and null our handler
202 packetService.removeProcessor(processor);
203 processor = null;
Ray Milkey75879ef2015-09-24 16:34:02 -0700204 StateMachine.destroyMaps();
Ray Milkey4ed93692015-10-07 14:37:17 -0700205 radiusSocket.close();
206 executor.shutdownNow();
Jian Li02e5ed62015-12-09 13:20:34 -0800207 log.info("Stopped");
Ray Milkey4ed93692015-10-07 14:37:17 -0700208 }
209
Jonathan Hartb92cc512015-11-16 23:05:21 -0800210 protected void sendRadiusPacket(RADIUS radiusPacket) {
Ray Milkey4ed93692015-10-07 14:37:17 -0700211
212 try {
213 final byte[] data = radiusPacket.serialize();
214 final DatagramSocket socket = radiusSocket;
215
216 DatagramPacket packet =
217 new DatagramPacket(data, data.length,
218 radiusIpAddress, radiusServerPort);
219
220 socket.send(packet);
221 } catch (IOException e) {
222 log.info("Cannot send packet to RADIUS server", e);
223 }
Ari Saha79d7c252015-06-26 10:31:48 -0700224 }
225
Jonathan Hart4a60bb32015-06-30 15:31:20 -0700226 /**
Aaron Kruglikov07a923d2015-07-03 13:30:57 -0700227 * Request packet in via PacketService.
228 */
229 private void requestIntercepts() {
230 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
231 selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
232 packetService.requestPackets(selector.build(),
233 CONTROL, appId);
234 }
235
236 /**
237 * Cancel request for packet in via PacketService.
238 */
239 private void withdrawIntercepts() {
240 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
241 selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
242 packetService.cancelPackets(selector.build(), CONTROL, appId);
243 }
244
Ray Milkey4ed93692015-10-07 14:37:17 -0700245 /**
246 * Send the ethernet packet to the supplicant.
247 *
248 * @param ethernetPkt the ethernet packet
249 * @param connectPoint the connect point to send out
250 */
251 private void sendPacketToSupplicant(Ethernet ethernetPkt, ConnectPoint connectPoint) {
252 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
253 OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(),
254 treatment, ByteBuffer.wrap(ethernetPkt.serialize()));
255 packetService.emit(packet);
256 }
257
Ari Saha79d7c252015-06-26 10:31:48 -0700258 // our handler defined as a private inner class
259
260 /**
261 * Packet processor responsible for forwarding packets along their paths.
262 */
263 private class ReactivePacketProcessor implements PacketProcessor {
264 @Override
265 public void process(PacketContext context) {
266
267 // Extract the original Ethernet frame from the packet information
268 InboundPacket pkt = context.inPacket();
269 Ethernet ethPkt = pkt.parsed();
270 if (ethPkt == null) {
271 return;
272 }
Ray Milkey1c0ea1a2015-09-25 10:24:23 -0700273 try {
274 // identify if incoming packet comes from supplicant (EAP) or RADIUS
275 switch (EthType.EtherType.lookup(ethPkt.getEtherType())) {
276 case EAPOL:
277 handleSupplicantPacket(context.inPacket());
278 break;
Ray Milkey1c0ea1a2015-09-25 10:24:23 -0700279 default:
280 log.trace("Skipping Ethernet packet type {}",
281 EthType.EtherType.lookup(ethPkt.getEtherType()));
282 }
Ray Milkey4ed93692015-10-07 14:37:17 -0700283 } catch (StateMachineException e) {
Ray Milkey1c0ea1a2015-09-25 10:24:23 -0700284 log.warn("Unable to process RADIUS packet:", e);
Ari Saha79d7c252015-06-26 10:31:48 -0700285 }
286 }
287
Ray Milkey7e5a2032015-09-30 15:09:17 -0700288 /**
289 * Creates and initializes common fields of a RADIUS packet.
290 *
Ray Milkey4ed93692015-10-07 14:37:17 -0700291 * @param stateMachine state machine for the request
Ray Milkey57f2e142015-10-01 16:48:18 -0700292 * @param eapPacket EAP packet
Ray Milkey7e5a2032015-09-30 15:09:17 -0700293 * @return RADIUS packet
294 */
Ray Milkey4ed93692015-10-07 14:37:17 -0700295 private RADIUS getRadiusPayload(StateMachine stateMachine, byte identifier, EAP eapPacket) {
Ray Milkey7e5a2032015-09-30 15:09:17 -0700296 RADIUS radiusPayload =
297 new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
298 eapPacket.getIdentifier());
Ray Milkey4ed93692015-10-07 14:37:17 -0700299
300 // set Request Authenticator in StateMachine
301 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
302
Ray Milkey7e5a2032015-09-30 15:09:17 -0700303 radiusPayload.setIdentifier(identifier);
304 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
Ray Milkey4ed93692015-10-07 14:37:17 -0700305 stateMachine.username());
Ray Milkey7e5a2032015-09-30 15:09:17 -0700306
307 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
Jonathan Hartb92cc512015-11-16 23:05:21 -0800308 AaaManager.this.nasIpAddress.getAddress());
Ray Milkey7e5a2032015-09-30 15:09:17 -0700309
310 radiusPayload.encapsulateMessage(eapPacket);
Ray Milkey7e5a2032015-09-30 15:09:17 -0700311
312 return radiusPayload;
313 }
Ari Saha79d7c252015-06-26 10:31:48 -0700314
315 /**
Jonathan Hart4a60bb32015-06-30 15:31:20 -0700316 * Handles PAE packets (supplicant).
317 *
318 * @param inPacket Ethernet packet coming from the supplicant
Ari Saha79d7c252015-06-26 10:31:48 -0700319 */
Ray Milkey1c0ea1a2015-09-25 10:24:23 -0700320 private void handleSupplicantPacket(InboundPacket inPacket) throws StateMachineException {
Jonathan Hart4a60bb32015-06-30 15:31:20 -0700321 Ethernet ethPkt = inPacket.parsed();
Ari Saha79d7c252015-06-26 10:31:48 -0700322 // Where does it come from?
Jonathan Hartb92cc512015-11-16 23:05:21 -0800323 MacAddress srcMac = ethPkt.getSourceMAC();
Ari Saha79d7c252015-06-26 10:31:48 -0700324
Jonathan Hart4a60bb32015-06-30 15:31:20 -0700325 DeviceId deviceId = inPacket.receivedFrom().deviceId();
326 PortNumber portNumber = inPacket.receivedFrom().port();
Ari Saha79d7c252015-06-26 10:31:48 -0700327 String sessionId = deviceId.toString() + portNumber.toString();
Ray Milkey75879ef2015-09-24 16:34:02 -0700328 StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
329 if (stateMachine == null) {
330 stateMachine = new StateMachine(sessionId, voltTenantService);
331 }
332
Jonathan Hart4a60bb32015-06-30 15:31:20 -0700333
334 EAPOL eapol = (EAPOL) ethPkt.getPayload();
Ari Saha79d7c252015-06-26 10:31:48 -0700335
336 switch (eapol.getEapolType()) {
337 case EAPOL.EAPOL_START:
Ray Milkey1c0ea1a2015-09-25 10:24:23 -0700338 stateMachine.start();
339 stateMachine.setSupplicantConnectpoint(inPacket.receivedFrom());
Ari Saha79d7c252015-06-26 10:31:48 -0700340
Ray Milkey1c0ea1a2015-09-25 10:24:23 -0700341 //send an EAP Request/Identify to the supplicant
342 EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.identifier(), EAP.ATTR_IDENTITY, null);
Jonathan Hartb92cc512015-11-16 23:05:21 -0800343 Ethernet eth = buildEapolResponse(srcMac, MacAddress.valueOf(nasMacAddress),
Ray Milkey1c0ea1a2015-09-25 10:24:23 -0700344 ethPkt.getVlanID(), EAPOL.EAPOL_PACKET,
345 eapPayload);
Jonathan Hartb92cc512015-11-16 23:05:21 -0800346 stateMachine.setSupplicantAddress(srcMac);
Ray Milkey1c0ea1a2015-09-25 10:24:23 -0700347 stateMachine.setVlanId(ethPkt.getVlanID());
Ari Saha79d7c252015-06-26 10:31:48 -0700348
Ray Milkey4ed93692015-10-07 14:37:17 -0700349 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
Ari Saha79d7c252015-06-26 10:31:48 -0700350
351 break;
Qianqian Hu33836df2015-12-23 20:44:48 +0800352 case EAPOL.EAPOL_LOGOFF:
353 if (stateMachine.state() == stateMachine.STATE_AUTHORIZED) {
354 try {
355 stateMachine.logoff();
356 } catch (StateMachineException e) {
357 e.printStackTrace();
358 }
359 }
360
361 break;
Ari Saha79d7c252015-06-26 10:31:48 -0700362 case EAPOL.EAPOL_PACKET:
Ray Milkey1c0ea1a2015-09-25 10:24:23 -0700363 RADIUS radiusPayload;
Ray Milkey7e5a2032015-09-30 15:09:17 -0700364 // check if this is a Response/Identify or a Response/TLS
Ari Saha79d7c252015-06-26 10:31:48 -0700365 EAP eapPacket = (EAP) eapol.getPayload();
366
367 byte dataType = eapPacket.getDataType();
368 switch (dataType) {
Ari Saha79d7c252015-06-26 10:31:48 -0700369
Ray Milkey7e5a2032015-09-30 15:09:17 -0700370 case EAP.ATTR_IDENTITY:
371 // request id access to RADIUS
372 stateMachine.setUsername(eapPacket.getData());
Ari Saha79d7c252015-06-26 10:31:48 -0700373
Ray Milkey4ed93692015-10-07 14:37:17 -0700374 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
Jonathan Hartb92cc512015-11-16 23:05:21 -0800375 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
Ari Saha79d7c252015-06-26 10:31:48 -0700376
Jonathan Hartb92cc512015-11-16 23:05:21 -0800377 sendRadiusPacket(radiusPayload);
Ray Milkey1c0ea1a2015-09-25 10:24:23 -0700378
Ray Milkey7e5a2032015-09-30 15:09:17 -0700379 // change the state to "PENDING"
380 stateMachine.requestAccess();
381 break;
Ari Saha79d7c252015-06-26 10:31:48 -0700382 case EAP.ATTR_MD5:
Ray Milkey7e5a2032015-09-30 15:09:17 -0700383 // verify if the EAP identifier corresponds to the
384 // challenge identifier from the client state
385 // machine.
Ray Milkey75879ef2015-09-24 16:34:02 -0700386 if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) {
Ari Saha79d7c252015-06-26 10:31:48 -0700387 //send the RADIUS challenge response
Ray Milkey4ed93692015-10-07 14:37:17 -0700388 radiusPayload =
389 getRadiusPayload(stateMachine,
390 stateMachine.identifier(),
391 eapPacket);
Ari Saha79d7c252015-06-26 10:31:48 -0700392
Qianqian Hu33836df2015-12-23 20:44:48 +0800393 if (stateMachine.challengeState() != null) {
394 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
395 stateMachine.challengeState());
396 }
Jonathan Hartb92cc512015-11-16 23:05:21 -0800397 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
398 sendRadiusPacket(radiusPayload);
Ari Saha79d7c252015-06-26 10:31:48 -0700399 }
400 break;
401 case EAP.ATTR_TLS:
Ray Milkey7e5a2032015-09-30 15:09:17 -0700402 // request id access to RADIUS
Ray Milkey4ed93692015-10-07 14:37:17 -0700403 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
Ari Saha79d7c252015-06-26 10:31:48 -0700404
Qianqian Hu33836df2015-12-23 20:44:48 +0800405 if (stateMachine.challengeState() != null) {
406 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
407 stateMachine.challengeState());
408 }
Ray Milkey1c0ea1a2015-09-25 10:24:23 -0700409 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
Ari Saha79d7c252015-06-26 10:31:48 -0700410
Jonathan Hartb92cc512015-11-16 23:05:21 -0800411 radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
412 sendRadiusPacket(radiusPayload);
Ray Milkeyd9dfe112015-10-21 12:13:49 -0700413
Ray Milkeyc3902fb2015-10-21 16:28:08 -0700414 if (stateMachine.state() != StateMachine.STATE_PENDING) {
415 stateMachine.requestAccess();
416 }
Ray Milkey1c0ea1a2015-09-25 10:24:23 -0700417
Ari Saha79d7c252015-06-26 10:31:48 -0700418 break;
419 default:
420 return;
421 }
422 break;
423 default:
Ray Milkey1c0ea1a2015-09-25 10:24:23 -0700424 log.trace("Skipping EAPOL message {}", eapol.getEapolType());
Ari Saha79d7c252015-06-26 10:31:48 -0700425 }
Ray Milkey4ed93692015-10-07 14:37:17 -0700426
Ari Saha79d7c252015-06-26 10:31:48 -0700427 }
Ray Milkey4ed93692015-10-07 14:37:17 -0700428 }
429
430 class RadiusListener implements Runnable {
Ari Saha79d7c252015-06-26 10:31:48 -0700431
432 /**
Jonathan Hart4a60bb32015-06-30 15:31:20 -0700433 * Handles RADIUS packets.
434 *
Ari Saha79d7c252015-06-26 10:31:48 -0700435 * @param radiusPacket RADIUS packet coming from the RADIUS server.
Ray Milkeye3026a42015-10-27 10:39:42 -0700436 * @throws StateMachineException if an illegal state transition is triggered
Ari Saha79d7c252015-06-26 10:31:48 -0700437 */
Ray Milkey4ed93692015-10-07 14:37:17 -0700438 protected void handleRadiusPacket(RADIUS radiusPacket) throws StateMachineException {
Ray Milkey75879ef2015-09-24 16:34:02 -0700439 StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier());
Ari Saha79d7c252015-06-26 10:31:48 -0700440 if (stateMachine == null) {
441 log.error("Invalid session identifier, exiting...");
442 return;
443 }
444
Ray Milkey1c0ea1a2015-09-25 10:24:23 -0700445 EAP eapPayload;
446 Ethernet eth;
Ari Saha79d7c252015-06-26 10:31:48 -0700447 switch (radiusPacket.getCode()) {
448 case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE:
Qianqian Hu33836df2015-12-23 20:44:48 +0800449 RADIUSAttribute radiusAttrState = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE);
450 byte[] challengeState = null;
451 if (radiusAttrState != null) {
452 challengeState = radiusAttrState.getValue();
453 }
Ari Saha79d7c252015-06-26 10:31:48 -0700454 eapPayload = radiusPacket.decapsulateMessage();
455 stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState);
Ray Milkey75879ef2015-09-24 16:34:02 -0700456 eth = buildEapolResponse(stateMachine.supplicantAddress(),
Ray Milkey4ed93692015-10-07 14:37:17 -0700457 MacAddress.valueOf(nasMacAddress),
458 stateMachine.vlanId(),
459 EAPOL.EAPOL_PACKET,
Aaron Kruglikov07a923d2015-07-03 13:30:57 -0700460 eapPayload);
Ray Milkey4ed93692015-10-07 14:37:17 -0700461 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
Ari Saha79d7c252015-06-26 10:31:48 -0700462 break;
463 case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
Ray Milkey1c0ea1a2015-09-25 10:24:23 -0700464 //send an EAPOL - Success to the supplicant.
465 byte[] eapMessage =
466 radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
467 eapPayload = new EAP();
468 eapPayload = (EAP) eapPayload.deserialize(eapMessage, 0, eapMessage.length);
469 eth = buildEapolResponse(stateMachine.supplicantAddress(),
Ray Milkey4ed93692015-10-07 14:37:17 -0700470 MacAddress.valueOf(nasMacAddress),
471 stateMachine.vlanId(),
472 EAPOL.EAPOL_PACKET,
Ray Milkey1c0ea1a2015-09-25 10:24:23 -0700473 eapPayload);
Ray Milkey4ed93692015-10-07 14:37:17 -0700474 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
Ari Saha79d7c252015-06-26 10:31:48 -0700475
Ray Milkey1c0ea1a2015-09-25 10:24:23 -0700476 stateMachine.authorizeAccess();
Ari Saha79d7c252015-06-26 10:31:48 -0700477 break;
478 case RADIUS.RADIUS_CODE_ACCESS_REJECT:
Ray Milkey1c0ea1a2015-09-25 10:24:23 -0700479 stateMachine.denyAccess();
Ari Saha79d7c252015-06-26 10:31:48 -0700480 break;
481 default:
482 log.warn("Unknown RADIUS message received with code: {}", radiusPacket.getCode());
483 }
484 }
485
Ari Saha79d7c252015-06-26 10:31:48 -0700486
Ray Milkey4ed93692015-10-07 14:37:17 -0700487 @Override
488 public void run() {
489 boolean done = false;
490 int packetNumber = 1;
491
492 log.info("UDP listener thread starting up");
493 RADIUS inboundRadiusPacket;
494 while (!done) {
495 try {
Ray Milkeyd9dfe112015-10-21 12:13:49 -0700496 byte[] packetBuffer = new byte[RADIUS.RADIUS_MAX_LENGTH];
497 DatagramPacket inboundBasePacket =
498 new DatagramPacket(packetBuffer, packetBuffer.length);
Ray Milkey4ed93692015-10-07 14:37:17 -0700499 DatagramSocket socket = radiusSocket;
500 socket.receive(inboundBasePacket);
501 log.info("Packet #{} received", packetNumber++);
502 try {
503 inboundRadiusPacket =
504 RADIUS.deserializer()
505 .deserialize(inboundBasePacket.getData(),
506 0,
507 inboundBasePacket.getLength());
508 handleRadiusPacket(inboundRadiusPacket);
509 } catch (DeserializationException dex) {
510 log.error("Cannot deserialize packet", dex);
511 } catch (StateMachineException sme) {
512 log.error("Illegal state machine operation", sme);
513 }
514
515 } catch (IOException e) {
516 log.info("Socket was closed, exiting listener thread");
517 done = true;
518 }
Ari Saha79d7c252015-06-26 10:31:48 -0700519 }
Ari Saha79d7c252015-06-26 10:31:48 -0700520 }
Ari Saha79d7c252015-06-26 10:31:48 -0700521 }
522
Ray Milkey4ed93692015-10-07 14:37:17 -0700523 RadiusListener radiusListener = new RadiusListener();
524
Ray Milkey57f2e142015-10-01 16:48:18 -0700525 private class InternalConfigListener implements NetworkConfigListener {
526
527 /**
528 * Reconfigures the DHCP Server according to the configuration parameters passed.
529 *
530 * @param cfg configuration object
531 */
Jonathan Hartb92cc512015-11-16 23:05:21 -0800532 private void reconfigureNetwork(AaaConfig cfg) {
533 AaaConfig newCfg;
Ray Milkey57f2e142015-10-01 16:48:18 -0700534 if (cfg == null) {
Jonathan Hartb92cc512015-11-16 23:05:21 -0800535 newCfg = new AaaConfig();
Ray Milkey57f2e142015-10-01 16:48:18 -0700536 } else {
537 newCfg = cfg;
538 }
539 if (newCfg.nasIp() != null) {
540 nasIpAddress = newCfg.nasIp();
541 }
542 if (newCfg.radiusIp() != null) {
543 radiusIpAddress = newCfg.radiusIp();
544 }
545 if (newCfg.radiusMac() != null) {
546 radiusMacAddress = newCfg.radiusMac();
547 }
548 if (newCfg.nasMac() != null) {
549 nasMacAddress = newCfg.nasMac();
550 }
551 if (newCfg.radiusSecret() != null) {
552 radiusSecret = newCfg.radiusSecret();
553 }
554 if (newCfg.radiusSwitch() != null) {
555 radiusSwitch = newCfg.radiusSwitch();
556 }
557 if (newCfg.radiusPort() != -1) {
558 radiusPort = newCfg.radiusPort();
559 }
Jonathan Hartb92cc512015-11-16 23:05:21 -0800560 if (newCfg.radiusServerUdpPort() != -1) {
561 radiusServerPort = newCfg.radiusServerUdpPort();
Ray Milkeyaf86fbf2015-10-06 15:41:30 -0700562 }
Ray Milkey57f2e142015-10-01 16:48:18 -0700563 }
564
565 @Override
566 public void event(NetworkConfigEvent event) {
567
568 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
569 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
Jonathan Hartb92cc512015-11-16 23:05:21 -0800570 event.configClass().equals(AaaConfig.class)) {
Ray Milkey57f2e142015-10-01 16:48:18 -0700571
Jonathan Hartb92cc512015-11-16 23:05:21 -0800572 AaaConfig cfg = netCfgService.getConfig(appId, AaaConfig.class);
Ray Milkey57f2e142015-10-01 16:48:18 -0700573 reconfigureNetwork(cfg);
574 log.info("Reconfigured");
575 }
576 }
577 }
578
579
Ari Saha79d7c252015-06-26 10:31:48 -0700580}