blob: 72a5b122ff5ff3bd1f98c6b88e85e30916134f3b [file] [log] [blame]
Ari Saha89831742015-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
Ray Milkey967776a2015-10-07 14:37:17 -070018import java.io.IOException;
19import java.net.DatagramPacket;
20import java.net.DatagramSocket;
Ray Milkeyf61a24e2015-09-24 16:34:02 -070021import java.net.InetAddress;
Ray Milkeyf61a24e2015-09-24 16:34:02 -070022import java.nio.ByteBuffer;
Ray Milkey967776a2015-10-07 14:37:17 -070023import java.util.concurrent.ExecutorService;
24import java.util.concurrent.Executors;
Ray Milkeyf61a24e2015-09-24 16:34:02 -070025
Ari Saha89831742015-06-26 10:31:48 -070026import org.apache.felix.scr.annotations.Activate;
27import org.apache.felix.scr.annotations.Component;
28import org.apache.felix.scr.annotations.Deactivate;
Ari Saha89831742015-06-26 10:31:48 -070029import org.apache.felix.scr.annotations.Reference;
30import org.apache.felix.scr.annotations.ReferenceCardinality;
Jonathan Harta46dddf2015-06-30 15:31:20 -070031import org.onlab.packet.DeserializationException;
32import 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;
41import org.onosproject.net.ConnectPoint;
42import org.onosproject.net.DeviceId;
Ari Saha89831742015-06-26 10:31:48 -070043import org.onosproject.net.PortNumber;
Ray Milkeyfcb623d2015-10-01 16:48:18 -070044import org.onosproject.net.config.ConfigFactory;
45import org.onosproject.net.config.NetworkConfigEvent;
46import org.onosproject.net.config.NetworkConfigListener;
47import org.onosproject.net.config.NetworkConfigRegistry;
Ari Saha89831742015-06-26 10:31:48 -070048import org.onosproject.net.flow.DefaultTrafficSelector;
49import org.onosproject.net.flow.DefaultTrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070050import org.onosproject.net.flow.TrafficSelector;
51import org.onosproject.net.flow.TrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070052import org.onosproject.net.packet.DefaultOutboundPacket;
53import org.onosproject.net.packet.InboundPacket;
54import org.onosproject.net.packet.OutboundPacket;
55import org.onosproject.net.packet.PacketContext;
Ari Saha89831742015-06-26 10:31:48 -070056import org.onosproject.net.packet.PacketProcessor;
57import org.onosproject.net.packet.PacketService;
Ari Saha89831742015-06-26 10:31:48 -070058import org.onosproject.xosintegration.VoltTenantService;
Ari Saha89831742015-06-26 10:31:48 -070059import org.slf4j.Logger;
60
Ray Milkey967776a2015-10-07 14:37:17 -070061import com.google.common.util.concurrent.ThreadFactoryBuilder;
62
Ray Milkeyfcb623d2015-10-01 16:48:18 -070063import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -070064import static org.onosproject.net.packet.PacketPriority.CONTROL;
Ari Saha89831742015-06-26 10:31:48 -070065import static org.slf4j.LoggerFactory.getLogger;
66
Ari Saha89831742015-06-26 10:31:48 -070067/**
Jonathan Harta46dddf2015-06-30 15:31:20 -070068 * AAA application for ONOS.
Ari Saha89831742015-06-26 10:31:48 -070069 */
70@Component(immediate = true)
71public class AAA {
Ray Milkeyf51eba22015-09-25 10:24:23 -070072
Ray Milkeyf61a24e2015-09-24 16:34:02 -070073 // for verbose output
74 private final Logger log = getLogger(getClass());
Ray Milkeyf51eba22015-09-25 10:24:23 -070075
Ray Milkeyf61a24e2015-09-24 16:34:02 -070076 // a list of our dependencies :
77 // to register with ONOS as an application - described next
78 @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 // to receive Packet-in events that we'll respond to
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected PacketService packetService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070084
Ray Milkeyf61a24e2015-09-24 16:34:02 -070085 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 protected VoltTenantService voltTenantService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070087
88 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkeyfcb623d2015-10-01 16:48:18 -070089 protected NetworkConfigRegistry netCfgService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070090
Ray Milkeyfcb623d2015-10-01 16:48:18 -070091 // Parsed RADIUS server addresses
92 protected InetAddress radiusIpAddress;
93 protected String radiusMacAddress;
94
95 // NAS IP address
96 protected InetAddress nasIpAddress;
97 protected String nasMacAddress;
98
99 // RADIUS server secret
100 protected String radiusSecret;
101
102 // ID of RADIUS switch
103 protected String radiusSwitch;
104
105 // RADIUS port number
106 protected long radiusPort;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700107
Ray Milkey5d99bd12015-10-06 15:41:30 -0700108 // RADIUS server TCP port number
109 protected short radiusServerPort;
110
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700111 // our application-specific event handler
112 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
Ray Milkeyf51eba22015-09-25 10:24:23 -0700113
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700114 // our unique identifier
115 private ApplicationId appId;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700116
Ray Milkey967776a2015-10-07 14:37:17 -0700117 // Socket used for UDP communications with RADIUS server
118 private DatagramSocket radiusSocket;
119
120 // Executor for RADIUS communication thread
121 private ExecutorService executor;
122
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700123 // Configuration properties factory
124 private final ConfigFactory factory =
125 new ConfigFactory<ApplicationId, AAAConfig>(APP_SUBJECT_FACTORY,
126 AAAConfig.class,
127 "AAA") {
128 @Override
129 public AAAConfig createConfig() {
130 return new AAAConfig();
131 }
132 };
Ray Milkeyf51eba22015-09-25 10:24:23 -0700133
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700134 // Listener for config changes
135 private final InternalConfigListener cfgListener = new InternalConfigListener();
Ari Saha89831742015-06-26 10:31:48 -0700136
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700137 /**
138 * Builds an EAPOL packet based on the given parameters.
139 *
140 * @param dstMac destination MAC address
141 * @param srcMac source MAC address
142 * @param vlan vlan identifier
143 * @param eapolType EAPOL type
144 * @param eap EAP payload
145 * @return Ethernet frame
146 */
147 private static Ethernet buildEapolResponse(MacAddress dstMac, MacAddress srcMac,
148 short vlan, byte eapolType, EAP eap) {
Ari Saha89831742015-06-26 10:31:48 -0700149
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700150 Ethernet eth = new Ethernet();
151 eth.setDestinationMACAddress(dstMac.toBytes());
152 eth.setSourceMACAddress(srcMac.toBytes());
153 eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
154 if (vlan != Ethernet.VLAN_UNTAGGED) {
155 eth.setVlanID(vlan);
156 }
157 //eapol header
158 EAPOL eapol = new EAPOL();
159 eapol.setEapolType(eapolType);
160 eapol.setPacketLength(eap.getLength());
Ari Saha89831742015-06-26 10:31:48 -0700161
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700162 //eap part
163 eapol.setPayload(eap);
164
165 eth.setPayload(eapol);
166 eth.setPad(true);
167 return eth;
168 }
Ari Saha89831742015-06-26 10:31:48 -0700169
Ari Saha89831742015-06-26 10:31:48 -0700170 @Activate
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700171 public void activate() {
172 netCfgService.addListener(cfgListener);
173 netCfgService.registerConfigFactory(factory);
174
Ari Saha89831742015-06-26 10:31:48 -0700175 // "org.onosproject.aaa" is the FQDN of our app
176 appId = coreService.registerApplication("org.onosproject.aaa");
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700177
178 cfgListener.reconfigureNetwork(netCfgService.getConfig(appId, AAAConfig.class));
179
Ari Saha89831742015-06-26 10:31:48 -0700180 // register our event handler
Brian O'Connord9c7da02015-07-29 17:49:24 -0700181 packetService.addProcessor(processor, PacketProcessor.director(2));
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700182 requestIntercepts();
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700183
184 StateMachine.initializeMaps();
Ari Saha89831742015-06-26 10:31:48 -0700185
Ray Milkey967776a2015-10-07 14:37:17 -0700186 try {
187 radiusSocket = new DatagramSocket(radiusServerPort);
188 } catch (Exception ex) {
189 log.error("Can't open RADIUS socket", ex);
190 }
191
192 executor = Executors.newSingleThreadExecutor(
193 new ThreadFactoryBuilder()
194 .setNameFormat("AAA-radius-%d").build());
195 executor.execute(radiusListener);
Ari Saha89831742015-06-26 10:31:48 -0700196 }
197
198 @Deactivate
199 public void deactivate() {
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700200 appId = coreService.registerApplication("org.onosproject.aaa");
201 withdrawIntercepts();
Ari Saha89831742015-06-26 10:31:48 -0700202 // de-register and null our handler
203 packetService.removeProcessor(processor);
204 processor = null;
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700205 StateMachine.destroyMaps();
Ray Milkey967776a2015-10-07 14:37:17 -0700206 radiusSocket.close();
207 executor.shutdownNow();
208 }
209
210 protected void sendRADIUSPacket(RADIUS radiusPacket) {
211
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 Saha89831742015-06-26 10:31:48 -0700224 }
225
Jonathan Harta46dddf2015-06-30 15:31:20 -0700226 /**
Aaron Kruglikovd39d99e2015-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 Milkey967776a2015-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 Saha89831742015-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 Milkeyf51eba22015-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 Milkeyf51eba22015-09-25 10:24:23 -0700279 default:
280 log.trace("Skipping Ethernet packet type {}",
281 EthType.EtherType.lookup(ethPkt.getEtherType()));
282 }
Ray Milkey967776a2015-10-07 14:37:17 -0700283 } catch (StateMachineException e) {
Ray Milkeyf51eba22015-09-25 10:24:23 -0700284 log.warn("Unable to process RADIUS packet:", e);
Ari Saha89831742015-06-26 10:31:48 -0700285 }
286 }
287
Ray Milkey9eb293f2015-09-30 15:09:17 -0700288 /**
289 * Creates and initializes common fields of a RADIUS packet.
290 *
Ray Milkey967776a2015-10-07 14:37:17 -0700291 * @param stateMachine state machine for the request
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700292 * @param eapPacket EAP packet
Ray Milkey9eb293f2015-09-30 15:09:17 -0700293 * @return RADIUS packet
294 */
Ray Milkey967776a2015-10-07 14:37:17 -0700295 private RADIUS getRadiusPayload(StateMachine stateMachine, byte identifier, EAP eapPacket) {
Ray Milkey9eb293f2015-09-30 15:09:17 -0700296 RADIUS radiusPayload =
297 new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
298 eapPacket.getIdentifier());
Ray Milkey967776a2015-10-07 14:37:17 -0700299
300 // set Request Authenticator in StateMachine
301 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
302
Ray Milkey9eb293f2015-09-30 15:09:17 -0700303 radiusPayload.setIdentifier(identifier);
304 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
Ray Milkey967776a2015-10-07 14:37:17 -0700305 stateMachine.username());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700306
307 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700308 AAA.this.nasIpAddress.getAddress());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700309
310 radiusPayload.encapsulateMessage(eapPacket);
Ray Milkey9eb293f2015-09-30 15:09:17 -0700311
312 return radiusPayload;
313 }
Ari Saha89831742015-06-26 10:31:48 -0700314
315 /**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700316 * Handles PAE packets (supplicant).
317 *
318 * @param inPacket Ethernet packet coming from the supplicant
Ari Saha89831742015-06-26 10:31:48 -0700319 */
Ray Milkeyf51eba22015-09-25 10:24:23 -0700320 private void handleSupplicantPacket(InboundPacket inPacket) throws StateMachineException {
Jonathan Harta46dddf2015-06-30 15:31:20 -0700321 Ethernet ethPkt = inPacket.parsed();
Ari Saha89831742015-06-26 10:31:48 -0700322 // Where does it come from?
323 MacAddress srcMAC = ethPkt.getSourceMAC();
324
Jonathan Harta46dddf2015-06-30 15:31:20 -0700325 DeviceId deviceId = inPacket.receivedFrom().deviceId();
326 PortNumber portNumber = inPacket.receivedFrom().port();
Ari Saha89831742015-06-26 10:31:48 -0700327 String sessionId = deviceId.toString() + portNumber.toString();
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700328 StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
329 if (stateMachine == null) {
330 stateMachine = new StateMachine(sessionId, voltTenantService);
331 }
332
Jonathan Harta46dddf2015-06-30 15:31:20 -0700333
334 EAPOL eapol = (EAPOL) ethPkt.getPayload();
Ari Saha89831742015-06-26 10:31:48 -0700335
336 switch (eapol.getEapolType()) {
337 case EAPOL.EAPOL_START:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700338 stateMachine.start();
339 stateMachine.setSupplicantConnectpoint(inPacket.receivedFrom());
Ari Saha89831742015-06-26 10:31:48 -0700340
Ray Milkeyf51eba22015-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);
Ray Milkey967776a2015-10-07 14:37:17 -0700343 Ethernet eth = buildEapolResponse(srcMAC, MacAddress.valueOf(nasMacAddress),
Ray Milkeyf51eba22015-09-25 10:24:23 -0700344 ethPkt.getVlanID(), EAPOL.EAPOL_PACKET,
345 eapPayload);
346 stateMachine.setSupplicantAddress(srcMAC);
347 stateMachine.setVlanId(ethPkt.getVlanID());
Ari Saha89831742015-06-26 10:31:48 -0700348
Ray Milkey967776a2015-10-07 14:37:17 -0700349 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
Ari Saha89831742015-06-26 10:31:48 -0700350
351 break;
352 case EAPOL.EAPOL_PACKET:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700353 RADIUS radiusPayload;
Ray Milkey9eb293f2015-09-30 15:09:17 -0700354 // check if this is a Response/Identify or a Response/TLS
Ari Saha89831742015-06-26 10:31:48 -0700355 EAP eapPacket = (EAP) eapol.getPayload();
356
357 byte dataType = eapPacket.getDataType();
358 switch (dataType) {
Ari Saha89831742015-06-26 10:31:48 -0700359
Ray Milkey9eb293f2015-09-30 15:09:17 -0700360 case EAP.ATTR_IDENTITY:
361 // request id access to RADIUS
362 stateMachine.setUsername(eapPacket.getData());
Ari Saha89831742015-06-26 10:31:48 -0700363
Ray Milkey967776a2015-10-07 14:37:17 -0700364 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
365 radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret);
Ari Saha89831742015-06-26 10:31:48 -0700366
Ray Milkey967776a2015-10-07 14:37:17 -0700367 sendRADIUSPacket(radiusPayload);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700368
Ray Milkey9eb293f2015-09-30 15:09:17 -0700369 // change the state to "PENDING"
370 stateMachine.requestAccess();
371 break;
Ari Saha89831742015-06-26 10:31:48 -0700372 case EAP.ATTR_MD5:
Ray Milkey9eb293f2015-09-30 15:09:17 -0700373 // verify if the EAP identifier corresponds to the
374 // challenge identifier from the client state
375 // machine.
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700376 if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) {
Ari Saha89831742015-06-26 10:31:48 -0700377 //send the RADIUS challenge response
Ray Milkey967776a2015-10-07 14:37:17 -0700378 radiusPayload =
379 getRadiusPayload(stateMachine,
380 stateMachine.identifier(),
381 eapPacket);
Ari Saha89831742015-06-26 10:31:48 -0700382
383 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700384 stateMachine.challengeState());
Ray Milkey967776a2015-10-07 14:37:17 -0700385 radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret);
386 sendRADIUSPacket(radiusPayload);
Ari Saha89831742015-06-26 10:31:48 -0700387 }
388 break;
389 case EAP.ATTR_TLS:
Ray Milkey9eb293f2015-09-30 15:09:17 -0700390 // request id access to RADIUS
Ray Milkey967776a2015-10-07 14:37:17 -0700391 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
Ari Saha89831742015-06-26 10:31:48 -0700392
Ray Milkeyf51eba22015-09-25 10:24:23 -0700393 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
394 stateMachine.challengeState());
395 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
Ari Saha89831742015-06-26 10:31:48 -0700396
Ray Milkey967776a2015-10-07 14:37:17 -0700397 radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret);
Ray Milkey5493b512015-10-21 12:13:49 -0700398 sendRADIUSPacket(radiusPayload);
399
Ray Milkeyf3790b82015-10-21 16:28:08 -0700400 if (stateMachine.state() != StateMachine.STATE_PENDING) {
401 stateMachine.requestAccess();
402 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700403
Ari Saha89831742015-06-26 10:31:48 -0700404 break;
405 default:
406 return;
407 }
408 break;
409 default:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700410 log.trace("Skipping EAPOL message {}", eapol.getEapolType());
Ari Saha89831742015-06-26 10:31:48 -0700411 }
Ray Milkey967776a2015-10-07 14:37:17 -0700412
Ari Saha89831742015-06-26 10:31:48 -0700413 }
Ray Milkey967776a2015-10-07 14:37:17 -0700414 }
415
416 class RadiusListener implements Runnable {
Ari Saha89831742015-06-26 10:31:48 -0700417
418 /**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700419 * Handles RADIUS packets.
420 *
Ari Saha89831742015-06-26 10:31:48 -0700421 * @param radiusPacket RADIUS packet coming from the RADIUS server.
422 */
Ray Milkey967776a2015-10-07 14:37:17 -0700423 protected void handleRadiusPacket(RADIUS radiusPacket) throws StateMachineException {
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700424 StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier());
Ari Saha89831742015-06-26 10:31:48 -0700425 if (stateMachine == null) {
426 log.error("Invalid session identifier, exiting...");
427 return;
428 }
429
Ray Milkeyf51eba22015-09-25 10:24:23 -0700430 EAP eapPayload;
431 Ethernet eth;
Ari Saha89831742015-06-26 10:31:48 -0700432 switch (radiusPacket.getCode()) {
433 case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE:
Ray Milkey967776a2015-10-07 14:37:17 -0700434 byte[] challengeState =
435 radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE).getValue();
Ari Saha89831742015-06-26 10:31:48 -0700436 eapPayload = radiusPacket.decapsulateMessage();
437 stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState);
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700438 eth = buildEapolResponse(stateMachine.supplicantAddress(),
Ray Milkey967776a2015-10-07 14:37:17 -0700439 MacAddress.valueOf(nasMacAddress),
440 stateMachine.vlanId(),
441 EAPOL.EAPOL_PACKET,
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700442 eapPayload);
Ray Milkey967776a2015-10-07 14:37:17 -0700443 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
Ari Saha89831742015-06-26 10:31:48 -0700444 break;
445 case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700446 //send an EAPOL - Success to the supplicant.
447 byte[] eapMessage =
448 radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
449 eapPayload = new EAP();
450 eapPayload = (EAP) eapPayload.deserialize(eapMessage, 0, eapMessage.length);
451 eth = buildEapolResponse(stateMachine.supplicantAddress(),
Ray Milkey967776a2015-10-07 14:37:17 -0700452 MacAddress.valueOf(nasMacAddress),
453 stateMachine.vlanId(),
454 EAPOL.EAPOL_PACKET,
Ray Milkeyf51eba22015-09-25 10:24:23 -0700455 eapPayload);
Ray Milkey967776a2015-10-07 14:37:17 -0700456 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
Ari Saha89831742015-06-26 10:31:48 -0700457
Ray Milkeyf51eba22015-09-25 10:24:23 -0700458 stateMachine.authorizeAccess();
Ari Saha89831742015-06-26 10:31:48 -0700459 break;
460 case RADIUS.RADIUS_CODE_ACCESS_REJECT:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700461 stateMachine.denyAccess();
Ari Saha89831742015-06-26 10:31:48 -0700462 break;
463 default:
464 log.warn("Unknown RADIUS message received with code: {}", radiusPacket.getCode());
465 }
466 }
467
Ari Saha89831742015-06-26 10:31:48 -0700468
Ray Milkey967776a2015-10-07 14:37:17 -0700469 @Override
470 public void run() {
471 boolean done = false;
472 int packetNumber = 1;
473
474 log.info("UDP listener thread starting up");
475 RADIUS inboundRadiusPacket;
476 while (!done) {
477 try {
Ray Milkey5493b512015-10-21 12:13:49 -0700478 byte[] packetBuffer = new byte[RADIUS.RADIUS_MAX_LENGTH];
479 DatagramPacket inboundBasePacket =
480 new DatagramPacket(packetBuffer, packetBuffer.length);
Ray Milkey967776a2015-10-07 14:37:17 -0700481 DatagramSocket socket = radiusSocket;
482 socket.receive(inboundBasePacket);
483 log.info("Packet #{} received", packetNumber++);
484 try {
485 inboundRadiusPacket =
486 RADIUS.deserializer()
487 .deserialize(inboundBasePacket.getData(),
488 0,
489 inboundBasePacket.getLength());
490 handleRadiusPacket(inboundRadiusPacket);
491 } catch (DeserializationException dex) {
492 log.error("Cannot deserialize packet", dex);
493 } catch (StateMachineException sme) {
494 log.error("Illegal state machine operation", sme);
495 }
496
497 } catch (IOException e) {
498 log.info("Socket was closed, exiting listener thread");
499 done = true;
500 }
Ari Saha89831742015-06-26 10:31:48 -0700501 }
Ari Saha89831742015-06-26 10:31:48 -0700502 }
Ari Saha89831742015-06-26 10:31:48 -0700503 }
504
Ray Milkey967776a2015-10-07 14:37:17 -0700505 RadiusListener radiusListener = new RadiusListener();
506
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700507 private class InternalConfigListener implements NetworkConfigListener {
508
509 /**
510 * Reconfigures the DHCP Server according to the configuration parameters passed.
511 *
512 * @param cfg configuration object
513 */
514 private void reconfigureNetwork(AAAConfig cfg) {
515 AAAConfig newCfg;
516 if (cfg == null) {
517 newCfg = new AAAConfig();
518 } else {
519 newCfg = cfg;
520 }
521 if (newCfg.nasIp() != null) {
522 nasIpAddress = newCfg.nasIp();
523 }
524 if (newCfg.radiusIp() != null) {
525 radiusIpAddress = newCfg.radiusIp();
526 }
527 if (newCfg.radiusMac() != null) {
528 radiusMacAddress = newCfg.radiusMac();
529 }
530 if (newCfg.nasMac() != null) {
531 nasMacAddress = newCfg.nasMac();
532 }
533 if (newCfg.radiusSecret() != null) {
534 radiusSecret = newCfg.radiusSecret();
535 }
536 if (newCfg.radiusSwitch() != null) {
537 radiusSwitch = newCfg.radiusSwitch();
538 }
539 if (newCfg.radiusPort() != -1) {
540 radiusPort = newCfg.radiusPort();
541 }
Ray Milkey5d99bd12015-10-06 15:41:30 -0700542 if (newCfg.radiusServerUDPPort() != -1) {
543 radiusServerPort = newCfg.radiusServerUDPPort();
544 }
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700545 }
546
547 @Override
548 public void event(NetworkConfigEvent event) {
549
550 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
551 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
552 event.configClass().equals(AAAConfig.class)) {
553
554 AAAConfig cfg = netCfgService.getConfig(appId, AAAConfig.class);
555 reconfigureNetwork(cfg);
556 log.info("Reconfigured");
557 }
558 }
559 }
560
561
Ari Saha89831742015-06-26 10:31:48 -0700562}