blob: caa98004e08d14c693913ba904f495eee7ddc572 [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;
36import org.onlab.packet.IPv4;
Ari Saha89831742015-06-26 10:31:48 -070037import org.onlab.packet.MacAddress;
Jonathan Harta46dddf2015-06-30 15:31:20 -070038import org.onlab.packet.RADIUS;
39import org.onlab.packet.RADIUSAttribute;
Hyunsun Moona0d63712015-08-22 21:04:23 -070040import org.onlab.packet.TpPort;
Ari Saha89831742015-06-26 10:31:48 -070041import org.onosproject.core.ApplicationId;
42import org.onosproject.core.CoreService;
43import 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;
Ari Saha89831742015-06-26 10:31:48 -070050import org.onosproject.net.flow.DefaultTrafficSelector;
51import org.onosproject.net.flow.DefaultTrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070052import org.onosproject.net.flow.TrafficSelector;
53import org.onosproject.net.flow.TrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070054import org.onosproject.net.packet.DefaultOutboundPacket;
55import org.onosproject.net.packet.InboundPacket;
56import org.onosproject.net.packet.OutboundPacket;
57import org.onosproject.net.packet.PacketContext;
Ari Saha89831742015-06-26 10:31:48 -070058import org.onosproject.net.packet.PacketProcessor;
59import org.onosproject.net.packet.PacketService;
Ari Saha89831742015-06-26 10:31:48 -070060import org.onosproject.xosintegration.VoltTenantService;
Ari Saha89831742015-06-26 10:31:48 -070061import org.slf4j.Logger;
62
Ray Milkey967776a2015-10-07 14:37:17 -070063import com.google.common.util.concurrent.ThreadFactoryBuilder;
64
Ray Milkeyfcb623d2015-10-01 16:48:18 -070065import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -070066import static org.onosproject.net.packet.PacketPriority.CONTROL;
Ari Saha89831742015-06-26 10:31:48 -070067import static org.slf4j.LoggerFactory.getLogger;
68
Ari Saha89831742015-06-26 10:31:48 -070069/**
Jonathan Harta46dddf2015-06-30 15:31:20 -070070 * AAA application for ONOS.
Ari Saha89831742015-06-26 10:31:48 -070071 */
72@Component(immediate = true)
73public class AAA {
Ray Milkeyf51eba22015-09-25 10:24:23 -070074
Ray Milkeyf61a24e2015-09-24 16:34:02 -070075 // for verbose output
76 private final Logger log = getLogger(getClass());
Ray Milkeyf51eba22015-09-25 10:24:23 -070077
Ray Milkeyf61a24e2015-09-24 16:34:02 -070078 // a list of our dependencies :
79 // to register with ONOS as an application - described next
80 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
81 protected CoreService coreService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070082
Ray Milkeyf61a24e2015-09-24 16:34:02 -070083 // to receive Packet-in events that we'll respond to
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 protected PacketService packetService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070086
Ray Milkeyf61a24e2015-09-24 16:34:02 -070087 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected VoltTenantService voltTenantService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070089
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkeyfcb623d2015-10-01 16:48:18 -070091 protected NetworkConfigRegistry netCfgService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070092
Ray Milkeyfcb623d2015-10-01 16:48:18 -070093 // Parsed RADIUS server addresses
94 protected InetAddress radiusIpAddress;
95 protected String radiusMacAddress;
96
97 // NAS IP address
98 protected InetAddress nasIpAddress;
99 protected String nasMacAddress;
100
101 // RADIUS server secret
102 protected String radiusSecret;
103
104 // ID of RADIUS switch
105 protected String radiusSwitch;
106
107 // RADIUS port number
108 protected long radiusPort;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700109
Ray Milkey5d99bd12015-10-06 15:41:30 -0700110 // RADIUS server TCP port number
111 protected short radiusServerPort;
112
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700113 // our application-specific event handler
114 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
Ray Milkeyf51eba22015-09-25 10:24:23 -0700115
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700116 // our unique identifier
117 private ApplicationId appId;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700118
Ray Milkey967776a2015-10-07 14:37:17 -0700119 // Socket used for UDP communications with RADIUS server
120 private DatagramSocket radiusSocket;
121
122 // Executor for RADIUS communication thread
123 private ExecutorService executor;
124
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700125 // Configuration properties factory
126 private final ConfigFactory factory =
127 new ConfigFactory<ApplicationId, AAAConfig>(APP_SUBJECT_FACTORY,
128 AAAConfig.class,
129 "AAA") {
130 @Override
131 public AAAConfig createConfig() {
132 return new AAAConfig();
133 }
134 };
Ray Milkeyf51eba22015-09-25 10:24:23 -0700135
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700136 // Listener for config changes
137 private final InternalConfigListener cfgListener = new InternalConfigListener();
Ari Saha89831742015-06-26 10:31:48 -0700138
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700139 /**
140 * Builds an EAPOL packet based on the given parameters.
141 *
142 * @param dstMac destination MAC address
143 * @param srcMac source MAC address
144 * @param vlan vlan identifier
145 * @param eapolType EAPOL type
146 * @param eap EAP payload
147 * @return Ethernet frame
148 */
149 private static Ethernet buildEapolResponse(MacAddress dstMac, MacAddress srcMac,
150 short vlan, byte eapolType, EAP eap) {
Ari Saha89831742015-06-26 10:31:48 -0700151
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700152 Ethernet eth = new Ethernet();
153 eth.setDestinationMACAddress(dstMac.toBytes());
154 eth.setSourceMACAddress(srcMac.toBytes());
155 eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
156 if (vlan != Ethernet.VLAN_UNTAGGED) {
157 eth.setVlanID(vlan);
158 }
159 //eapol header
160 EAPOL eapol = new EAPOL();
161 eapol.setEapolType(eapolType);
162 eapol.setPacketLength(eap.getLength());
Ari Saha89831742015-06-26 10:31:48 -0700163
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700164 //eap part
165 eapol.setPayload(eap);
166
167 eth.setPayload(eapol);
168 eth.setPad(true);
169 return eth;
170 }
Ari Saha89831742015-06-26 10:31:48 -0700171
Ari Saha89831742015-06-26 10:31:48 -0700172 @Activate
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700173 public void activate() {
174 netCfgService.addListener(cfgListener);
175 netCfgService.registerConfigFactory(factory);
176
Ari Saha89831742015-06-26 10:31:48 -0700177 // "org.onosproject.aaa" is the FQDN of our app
178 appId = coreService.registerApplication("org.onosproject.aaa");
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700179
180 cfgListener.reconfigureNetwork(netCfgService.getConfig(appId, AAAConfig.class));
181
Ari Saha89831742015-06-26 10:31:48 -0700182 // register our event handler
Brian O'Connord9c7da02015-07-29 17:49:24 -0700183 packetService.addProcessor(processor, PacketProcessor.director(2));
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700184 requestIntercepts();
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700185
186 StateMachine.initializeMaps();
Ari Saha89831742015-06-26 10:31:48 -0700187
Ray Milkey967776a2015-10-07 14:37:17 -0700188 try {
189 radiusSocket = new DatagramSocket(radiusServerPort);
190 } catch (Exception ex) {
191 log.error("Can't open RADIUS socket", ex);
192 }
193
194 executor = Executors.newSingleThreadExecutor(
195 new ThreadFactoryBuilder()
196 .setNameFormat("AAA-radius-%d").build());
197 executor.execute(radiusListener);
Ari Saha89831742015-06-26 10:31:48 -0700198 }
199
200 @Deactivate
201 public void deactivate() {
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700202 appId = coreService.registerApplication("org.onosproject.aaa");
203 withdrawIntercepts();
Ari Saha89831742015-06-26 10:31:48 -0700204 // de-register and null our handler
205 packetService.removeProcessor(processor);
206 processor = null;
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700207 StateMachine.destroyMaps();
Ray Milkey967776a2015-10-07 14:37:17 -0700208 radiusSocket.close();
209 executor.shutdownNow();
210 }
211
212 protected void sendRADIUSPacket(RADIUS radiusPacket) {
213
214 try {
215 final byte[] data = radiusPacket.serialize();
216 final DatagramSocket socket = radiusSocket;
217
218 DatagramPacket packet =
219 new DatagramPacket(data, data.length,
220 radiusIpAddress, radiusServerPort);
221
222 socket.send(packet);
223 } catch (IOException e) {
224 log.info("Cannot send packet to RADIUS server", e);
225 }
Ari Saha89831742015-06-26 10:31:48 -0700226 }
227
Jonathan Harta46dddf2015-06-30 15:31:20 -0700228 /**
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700229 * Request packet in via PacketService.
230 */
231 private void requestIntercepts() {
232 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
233 selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
234 packetService.requestPackets(selector.build(),
235 CONTROL, appId);
Jonathan Hartfeb41762015-07-15 15:10:28 -0700236
237 TrafficSelector radSelector = DefaultTrafficSelector.builder()
238 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
239 .matchIPProtocol(IPv4.PROTOCOL_UDP)
Ray Milkey5d99bd12015-10-06 15:41:30 -0700240 .matchUdpDst(TpPort.tpPort(radiusServerPort))
241 .matchUdpSrc(TpPort.tpPort(radiusServerPort))
Jonathan Hartfeb41762015-07-15 15:10:28 -0700242 .build();
243 packetService.requestPackets(radSelector, CONTROL, appId);
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700244 }
245
246 /**
247 * Cancel request for packet in via PacketService.
248 */
249 private void withdrawIntercepts() {
250 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
251 selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
252 packetService.cancelPackets(selector.build(), CONTROL, appId);
Jonathan Hartfeb41762015-07-15 15:10:28 -0700253
254 TrafficSelector radSelector = DefaultTrafficSelector.builder()
255 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
256 .matchIPProtocol(IPv4.PROTOCOL_UDP)
Ray Milkey5d99bd12015-10-06 15:41:30 -0700257 .matchUdpDst(TpPort.tpPort(radiusServerPort))
258 .matchUdpSrc(TpPort.tpPort(radiusServerPort))
Jonathan Hartfeb41762015-07-15 15:10:28 -0700259 .build();
260 packetService.cancelPackets(radSelector, CONTROL, appId);
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700261 }
262
Ray Milkey967776a2015-10-07 14:37:17 -0700263 /**
264 * Send the ethernet packet to the supplicant.
265 *
266 * @param ethernetPkt the ethernet packet
267 * @param connectPoint the connect point to send out
268 */
269 private void sendPacketToSupplicant(Ethernet ethernetPkt, ConnectPoint connectPoint) {
270 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
271 OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(),
272 treatment, ByteBuffer.wrap(ethernetPkt.serialize()));
273 packetService.emit(packet);
274 }
275
Ari Saha89831742015-06-26 10:31:48 -0700276 // our handler defined as a private inner class
277
278 /**
279 * Packet processor responsible for forwarding packets along their paths.
280 */
281 private class ReactivePacketProcessor implements PacketProcessor {
282 @Override
283 public void process(PacketContext context) {
284
285 // Extract the original Ethernet frame from the packet information
286 InboundPacket pkt = context.inPacket();
287 Ethernet ethPkt = pkt.parsed();
288 if (ethPkt == null) {
289 return;
290 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700291 try {
292 // identify if incoming packet comes from supplicant (EAP) or RADIUS
293 switch (EthType.EtherType.lookup(ethPkt.getEtherType())) {
294 case EAPOL:
295 handleSupplicantPacket(context.inPacket());
296 break;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700297 default:
298 log.trace("Skipping Ethernet packet type {}",
299 EthType.EtherType.lookup(ethPkt.getEtherType()));
300 }
Ray Milkey967776a2015-10-07 14:37:17 -0700301 } catch (StateMachineException e) {
Ray Milkeyf51eba22015-09-25 10:24:23 -0700302 log.warn("Unable to process RADIUS packet:", e);
Ari Saha89831742015-06-26 10:31:48 -0700303 }
304 }
305
Ray Milkey9eb293f2015-09-30 15:09:17 -0700306 /**
307 * Creates and initializes common fields of a RADIUS packet.
308 *
Ray Milkey967776a2015-10-07 14:37:17 -0700309 * @param stateMachine state machine for the request
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700310 * @param eapPacket EAP packet
Ray Milkey9eb293f2015-09-30 15:09:17 -0700311 * @return RADIUS packet
312 */
Ray Milkey967776a2015-10-07 14:37:17 -0700313 private RADIUS getRadiusPayload(StateMachine stateMachine, byte identifier, EAP eapPacket) {
Ray Milkey9eb293f2015-09-30 15:09:17 -0700314 RADIUS radiusPayload =
315 new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
316 eapPacket.getIdentifier());
Ray Milkey967776a2015-10-07 14:37:17 -0700317
318 // set Request Authenticator in StateMachine
319 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
320
Ray Milkey9eb293f2015-09-30 15:09:17 -0700321 radiusPayload.setIdentifier(identifier);
322 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
Ray Milkey967776a2015-10-07 14:37:17 -0700323 stateMachine.username());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700324
325 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700326 AAA.this.nasIpAddress.getAddress());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700327
328 radiusPayload.encapsulateMessage(eapPacket);
Ray Milkey9eb293f2015-09-30 15:09:17 -0700329
330 return radiusPayload;
331 }
Ari Saha89831742015-06-26 10:31:48 -0700332
333 /**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700334 * Handles PAE packets (supplicant).
335 *
336 * @param inPacket Ethernet packet coming from the supplicant
Ari Saha89831742015-06-26 10:31:48 -0700337 */
Ray Milkeyf51eba22015-09-25 10:24:23 -0700338 private void handleSupplicantPacket(InboundPacket inPacket) throws StateMachineException {
Jonathan Harta46dddf2015-06-30 15:31:20 -0700339 Ethernet ethPkt = inPacket.parsed();
Ari Saha89831742015-06-26 10:31:48 -0700340 // Where does it come from?
341 MacAddress srcMAC = ethPkt.getSourceMAC();
342
Jonathan Harta46dddf2015-06-30 15:31:20 -0700343 DeviceId deviceId = inPacket.receivedFrom().deviceId();
344 PortNumber portNumber = inPacket.receivedFrom().port();
Ari Saha89831742015-06-26 10:31:48 -0700345 String sessionId = deviceId.toString() + portNumber.toString();
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700346 StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
347 if (stateMachine == null) {
348 stateMachine = new StateMachine(sessionId, voltTenantService);
349 }
350
Jonathan Harta46dddf2015-06-30 15:31:20 -0700351
352 EAPOL eapol = (EAPOL) ethPkt.getPayload();
Ari Saha89831742015-06-26 10:31:48 -0700353
354 switch (eapol.getEapolType()) {
355 case EAPOL.EAPOL_START:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700356 stateMachine.start();
357 stateMachine.setSupplicantConnectpoint(inPacket.receivedFrom());
Ari Saha89831742015-06-26 10:31:48 -0700358
Ray Milkeyf51eba22015-09-25 10:24:23 -0700359 //send an EAP Request/Identify to the supplicant
360 EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.identifier(), EAP.ATTR_IDENTITY, null);
Ray Milkey967776a2015-10-07 14:37:17 -0700361 Ethernet eth = buildEapolResponse(srcMAC, MacAddress.valueOf(nasMacAddress),
Ray Milkeyf51eba22015-09-25 10:24:23 -0700362 ethPkt.getVlanID(), EAPOL.EAPOL_PACKET,
363 eapPayload);
364 stateMachine.setSupplicantAddress(srcMAC);
365 stateMachine.setVlanId(ethPkt.getVlanID());
Ari Saha89831742015-06-26 10:31:48 -0700366
Ray Milkey967776a2015-10-07 14:37:17 -0700367 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
Ari Saha89831742015-06-26 10:31:48 -0700368
369 break;
370 case EAPOL.EAPOL_PACKET:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700371 RADIUS radiusPayload;
Ray Milkey9eb293f2015-09-30 15:09:17 -0700372 // check if this is a Response/Identify or a Response/TLS
Ari Saha89831742015-06-26 10:31:48 -0700373 EAP eapPacket = (EAP) eapol.getPayload();
374
375 byte dataType = eapPacket.getDataType();
376 switch (dataType) {
Ari Saha89831742015-06-26 10:31:48 -0700377
Ray Milkey9eb293f2015-09-30 15:09:17 -0700378 case EAP.ATTR_IDENTITY:
379 // request id access to RADIUS
380 stateMachine.setUsername(eapPacket.getData());
Ari Saha89831742015-06-26 10:31:48 -0700381
Ray Milkey967776a2015-10-07 14:37:17 -0700382 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
383 radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret);
Ari Saha89831742015-06-26 10:31:48 -0700384
Ray Milkey967776a2015-10-07 14:37:17 -0700385 sendRADIUSPacket(radiusPayload);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700386
Ray Milkey9eb293f2015-09-30 15:09:17 -0700387 // change the state to "PENDING"
388 stateMachine.requestAccess();
389 break;
Ari Saha89831742015-06-26 10:31:48 -0700390 case EAP.ATTR_MD5:
Ray Milkey9eb293f2015-09-30 15:09:17 -0700391 // verify if the EAP identifier corresponds to the
392 // challenge identifier from the client state
393 // machine.
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700394 if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) {
Ari Saha89831742015-06-26 10:31:48 -0700395 //send the RADIUS challenge response
Ray Milkey967776a2015-10-07 14:37:17 -0700396 radiusPayload =
397 getRadiusPayload(stateMachine,
398 stateMachine.identifier(),
399 eapPacket);
Ari Saha89831742015-06-26 10:31:48 -0700400
401 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700402 stateMachine.challengeState());
Ray Milkey967776a2015-10-07 14:37:17 -0700403 radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret);
404 sendRADIUSPacket(radiusPayload);
Ari Saha89831742015-06-26 10:31:48 -0700405 }
406 break;
407 case EAP.ATTR_TLS:
Ray Milkey9eb293f2015-09-30 15:09:17 -0700408 // request id access to RADIUS
Ray Milkey967776a2015-10-07 14:37:17 -0700409 radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
Ari Saha89831742015-06-26 10:31:48 -0700410
Ray Milkeyf51eba22015-09-25 10:24:23 -0700411 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
412 stateMachine.challengeState());
413 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
Ari Saha89831742015-06-26 10:31:48 -0700414
Ray Milkey967776a2015-10-07 14:37:17 -0700415 sendRADIUSPacket(radiusPayload);
416 radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700417 // TODO: this gets called on every fragment, should only be called at TLS-Start
418 stateMachine.requestAccess();
419
Ari Saha89831742015-06-26 10:31:48 -0700420 break;
421 default:
422 return;
423 }
424 break;
425 default:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700426 log.trace("Skipping EAPOL message {}", eapol.getEapolType());
Ari Saha89831742015-06-26 10:31:48 -0700427 }
Ray Milkey967776a2015-10-07 14:37:17 -0700428
Ari Saha89831742015-06-26 10:31:48 -0700429 }
Ray Milkey967776a2015-10-07 14:37:17 -0700430 }
431
432 class RadiusListener implements Runnable {
Ari Saha89831742015-06-26 10:31:48 -0700433
434 /**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700435 * Handles RADIUS packets.
436 *
Ari Saha89831742015-06-26 10:31:48 -0700437 * @param radiusPacket RADIUS packet coming from the RADIUS server.
438 */
Ray Milkey967776a2015-10-07 14:37:17 -0700439 protected void handleRadiusPacket(RADIUS radiusPacket) throws StateMachineException {
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700440 StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier());
Ari Saha89831742015-06-26 10:31:48 -0700441 if (stateMachine == null) {
442 log.error("Invalid session identifier, exiting...");
443 return;
444 }
445
Ray Milkeyf51eba22015-09-25 10:24:23 -0700446 EAP eapPayload;
447 Ethernet eth;
Ari Saha89831742015-06-26 10:31:48 -0700448 switch (radiusPacket.getCode()) {
449 case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE:
Ray Milkey967776a2015-10-07 14:37:17 -0700450 byte[] challengeState =
451 radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE).getValue();
Ari Saha89831742015-06-26 10:31:48 -0700452 eapPayload = radiusPacket.decapsulateMessage();
453 stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState);
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700454 eth = buildEapolResponse(stateMachine.supplicantAddress(),
Ray Milkey967776a2015-10-07 14:37:17 -0700455 MacAddress.valueOf(nasMacAddress),
456 stateMachine.vlanId(),
457 EAPOL.EAPOL_PACKET,
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700458 eapPayload);
Ray Milkey967776a2015-10-07 14:37:17 -0700459 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
Ari Saha89831742015-06-26 10:31:48 -0700460 break;
461 case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700462 //send an EAPOL - Success to the supplicant.
463 byte[] eapMessage =
464 radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
465 eapPayload = new EAP();
466 eapPayload = (EAP) eapPayload.deserialize(eapMessage, 0, eapMessage.length);
467 eth = buildEapolResponse(stateMachine.supplicantAddress(),
Ray Milkey967776a2015-10-07 14:37:17 -0700468 MacAddress.valueOf(nasMacAddress),
469 stateMachine.vlanId(),
470 EAPOL.EAPOL_PACKET,
Ray Milkeyf51eba22015-09-25 10:24:23 -0700471 eapPayload);
Ray Milkey967776a2015-10-07 14:37:17 -0700472 sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
Ari Saha89831742015-06-26 10:31:48 -0700473
Ray Milkeyf51eba22015-09-25 10:24:23 -0700474 stateMachine.authorizeAccess();
Ari Saha89831742015-06-26 10:31:48 -0700475 break;
476 case RADIUS.RADIUS_CODE_ACCESS_REJECT:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700477 stateMachine.denyAccess();
Ari Saha89831742015-06-26 10:31:48 -0700478 break;
479 default:
480 log.warn("Unknown RADIUS message received with code: {}", radiusPacket.getCode());
481 }
482 }
483
Ari Saha89831742015-06-26 10:31:48 -0700484
Ray Milkey967776a2015-10-07 14:37:17 -0700485 @Override
486 public void run() {
487 boolean done = false;
488 int packetNumber = 1;
489
490 log.info("UDP listener thread starting up");
491 RADIUS inboundRadiusPacket;
492 while (!done) {
493 try {
494 DatagramPacket inboundBasePacket = new DatagramPacket(new byte[1000], 1000);
495 DatagramSocket socket = radiusSocket;
496 socket.receive(inboundBasePacket);
497 log.info("Packet #{} received", packetNumber++);
498 try {
499 inboundRadiusPacket =
500 RADIUS.deserializer()
501 .deserialize(inboundBasePacket.getData(),
502 0,
503 inboundBasePacket.getLength());
504 handleRadiusPacket(inboundRadiusPacket);
505 } catch (DeserializationException dex) {
506 log.error("Cannot deserialize packet", dex);
507 } catch (StateMachineException sme) {
508 log.error("Illegal state machine operation", sme);
509 }
510
511 } catch (IOException e) {
512 log.info("Socket was closed, exiting listener thread");
513 done = true;
514 }
Ari Saha89831742015-06-26 10:31:48 -0700515 }
Ari Saha89831742015-06-26 10:31:48 -0700516 }
Ari Saha89831742015-06-26 10:31:48 -0700517 }
518
Ray Milkey967776a2015-10-07 14:37:17 -0700519 RadiusListener radiusListener = new RadiusListener();
520
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700521 private class InternalConfigListener implements NetworkConfigListener {
522
523 /**
524 * Reconfigures the DHCP Server according to the configuration parameters passed.
525 *
526 * @param cfg configuration object
527 */
528 private void reconfigureNetwork(AAAConfig cfg) {
529 AAAConfig newCfg;
530 if (cfg == null) {
531 newCfg = new AAAConfig();
532 } else {
533 newCfg = cfg;
534 }
535 if (newCfg.nasIp() != null) {
536 nasIpAddress = newCfg.nasIp();
537 }
538 if (newCfg.radiusIp() != null) {
539 radiusIpAddress = newCfg.radiusIp();
540 }
541 if (newCfg.radiusMac() != null) {
542 radiusMacAddress = newCfg.radiusMac();
543 }
544 if (newCfg.nasMac() != null) {
545 nasMacAddress = newCfg.nasMac();
546 }
547 if (newCfg.radiusSecret() != null) {
548 radiusSecret = newCfg.radiusSecret();
549 }
550 if (newCfg.radiusSwitch() != null) {
551 radiusSwitch = newCfg.radiusSwitch();
552 }
553 if (newCfg.radiusPort() != -1) {
554 radiusPort = newCfg.radiusPort();
555 }
Ray Milkey5d99bd12015-10-06 15:41:30 -0700556 if (newCfg.radiusServerUDPPort() != -1) {
557 radiusServerPort = newCfg.radiusServerUDPPort();
558 }
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700559 }
560
561 @Override
562 public void event(NetworkConfigEvent event) {
563
564 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
565 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
566 event.configClass().equals(AAAConfig.class)) {
567
568 AAAConfig cfg = netCfgService.getConfig(appId, AAAConfig.class);
569 reconfigureNetwork(cfg);
570 log.info("Reconfigured");
571 }
572 }
573 }
574
575
Ari Saha89831742015-06-26 10:31:48 -0700576}