Committed by
Gerrit Code Review
Support RADIUS server outside of the ONOS network
Change-Id: I7e64faae6831467e084db878e02023d40fb33f07
Showing
6 changed files
with
564 additions
and
410 deletions
... | @@ -15,10 +15,13 @@ | ... | @@ -15,10 +15,13 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.aaa; | 16 | package org.onosproject.aaa; |
17 | 17 | ||
18 | +import java.io.IOException; | ||
19 | +import java.net.DatagramPacket; | ||
20 | +import java.net.DatagramSocket; | ||
18 | import java.net.InetAddress; | 21 | import java.net.InetAddress; |
19 | import java.nio.ByteBuffer; | 22 | import java.nio.ByteBuffer; |
20 | -import java.util.Optional; | 23 | +import java.util.concurrent.ExecutorService; |
21 | -import java.util.Set; | 24 | +import java.util.concurrent.Executors; |
22 | 25 | ||
23 | import org.apache.felix.scr.annotations.Activate; | 26 | import org.apache.felix.scr.annotations.Activate; |
24 | import org.apache.felix.scr.annotations.Component; | 27 | import org.apache.felix.scr.annotations.Component; |
... | @@ -31,19 +34,14 @@ import org.onlab.packet.EAPOL; | ... | @@ -31,19 +34,14 @@ import org.onlab.packet.EAPOL; |
31 | import org.onlab.packet.EthType; | 34 | import org.onlab.packet.EthType; |
32 | import org.onlab.packet.Ethernet; | 35 | import org.onlab.packet.Ethernet; |
33 | import org.onlab.packet.IPv4; | 36 | import org.onlab.packet.IPv4; |
34 | -import org.onlab.packet.Ip4Address; | ||
35 | -import org.onlab.packet.IpAddress; | ||
36 | import org.onlab.packet.MacAddress; | 37 | import org.onlab.packet.MacAddress; |
37 | import org.onlab.packet.RADIUS; | 38 | import org.onlab.packet.RADIUS; |
38 | import org.onlab.packet.RADIUSAttribute; | 39 | import org.onlab.packet.RADIUSAttribute; |
39 | import org.onlab.packet.TpPort; | 40 | import org.onlab.packet.TpPort; |
40 | -import org.onlab.packet.UDP; | ||
41 | -import org.onlab.packet.VlanId; | ||
42 | import org.onosproject.core.ApplicationId; | 41 | import org.onosproject.core.ApplicationId; |
43 | import org.onosproject.core.CoreService; | 42 | import org.onosproject.core.CoreService; |
44 | import org.onosproject.net.ConnectPoint; | 43 | import org.onosproject.net.ConnectPoint; |
45 | import org.onosproject.net.DeviceId; | 44 | import org.onosproject.net.DeviceId; |
46 | -import org.onosproject.net.Host; | ||
47 | import org.onosproject.net.PortNumber; | 45 | import org.onosproject.net.PortNumber; |
48 | import org.onosproject.net.config.ConfigFactory; | 46 | import org.onosproject.net.config.ConfigFactory; |
49 | import org.onosproject.net.config.NetworkConfigEvent; | 47 | import org.onosproject.net.config.NetworkConfigEvent; |
... | @@ -53,7 +51,6 @@ import org.onosproject.net.flow.DefaultTrafficSelector; | ... | @@ -53,7 +51,6 @@ import org.onosproject.net.flow.DefaultTrafficSelector; |
53 | import org.onosproject.net.flow.DefaultTrafficTreatment; | 51 | import org.onosproject.net.flow.DefaultTrafficTreatment; |
54 | import org.onosproject.net.flow.TrafficSelector; | 52 | import org.onosproject.net.flow.TrafficSelector; |
55 | import org.onosproject.net.flow.TrafficTreatment; | 53 | import org.onosproject.net.flow.TrafficTreatment; |
56 | -import org.onosproject.net.host.HostService; | ||
57 | import org.onosproject.net.packet.DefaultOutboundPacket; | 54 | import org.onosproject.net.packet.DefaultOutboundPacket; |
58 | import org.onosproject.net.packet.InboundPacket; | 55 | import org.onosproject.net.packet.InboundPacket; |
59 | import org.onosproject.net.packet.OutboundPacket; | 56 | import org.onosproject.net.packet.OutboundPacket; |
... | @@ -63,6 +60,8 @@ import org.onosproject.net.packet.PacketService; | ... | @@ -63,6 +60,8 @@ import org.onosproject.net.packet.PacketService; |
63 | import org.onosproject.xosintegration.VoltTenantService; | 60 | import org.onosproject.xosintegration.VoltTenantService; |
64 | import org.slf4j.Logger; | 61 | import org.slf4j.Logger; |
65 | 62 | ||
63 | +import com.google.common.util.concurrent.ThreadFactoryBuilder; | ||
64 | + | ||
66 | import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY; | 65 | import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY; |
67 | import static org.onosproject.net.packet.PacketPriority.CONTROL; | 66 | import static org.onosproject.net.packet.PacketPriority.CONTROL; |
68 | import static org.slf4j.LoggerFactory.getLogger; | 67 | import static org.slf4j.LoggerFactory.getLogger; |
... | @@ -85,10 +84,6 @@ public class AAA { | ... | @@ -85,10 +84,6 @@ public class AAA { |
85 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 84 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
86 | protected PacketService packetService; | 85 | protected PacketService packetService; |
87 | 86 | ||
88 | - // end host information | ||
89 | - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
90 | - protected HostService hostService; | ||
91 | - | ||
92 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 87 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
93 | protected VoltTenantService voltTenantService; | 88 | protected VoltTenantService voltTenantService; |
94 | 89 | ||
... | @@ -121,6 +116,12 @@ public class AAA { | ... | @@ -121,6 +116,12 @@ public class AAA { |
121 | // our unique identifier | 116 | // our unique identifier |
122 | private ApplicationId appId; | 117 | private ApplicationId appId; |
123 | 118 | ||
119 | + // Socket used for UDP communications with RADIUS server | ||
120 | + private DatagramSocket radiusSocket; | ||
121 | + | ||
122 | + // Executor for RADIUS communication thread | ||
123 | + private ExecutorService executor; | ||
124 | + | ||
124 | // Configuration properties factory | 125 | // Configuration properties factory |
125 | private final ConfigFactory factory = | 126 | private final ConfigFactory factory = |
126 | new ConfigFactory<ApplicationId, AAAConfig>(APP_SUBJECT_FACTORY, | 127 | new ConfigFactory<ApplicationId, AAAConfig>(APP_SUBJECT_FACTORY, |
... | @@ -184,7 +185,16 @@ public class AAA { | ... | @@ -184,7 +185,16 @@ public class AAA { |
184 | 185 | ||
185 | StateMachine.initializeMaps(); | 186 | StateMachine.initializeMaps(); |
186 | 187 | ||
187 | - hostService.startMonitoringIp(IpAddress.valueOf(radiusIpAddress)); | 188 | + 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); | ||
188 | } | 198 | } |
189 | 199 | ||
190 | @Deactivate | 200 | @Deactivate |
... | @@ -195,6 +205,24 @@ public class AAA { | ... | @@ -195,6 +205,24 @@ public class AAA { |
195 | packetService.removeProcessor(processor); | 205 | packetService.removeProcessor(processor); |
196 | processor = null; | 206 | processor = null; |
197 | StateMachine.destroyMaps(); | 207 | StateMachine.destroyMaps(); |
208 | + 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 | + } | ||
198 | } | 226 | } |
199 | 227 | ||
200 | /** | 228 | /** |
... | @@ -232,6 +260,19 @@ public class AAA { | ... | @@ -232,6 +260,19 @@ public class AAA { |
232 | packetService.cancelPackets(radSelector, CONTROL, appId); | 260 | packetService.cancelPackets(radSelector, CONTROL, appId); |
233 | } | 261 | } |
234 | 262 | ||
263 | + /** | ||
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 | + | ||
235 | // our handler defined as a private inner class | 276 | // our handler defined as a private inner class |
236 | 277 | ||
237 | /** | 278 | /** |
... | @@ -253,26 +294,11 @@ public class AAA { | ... | @@ -253,26 +294,11 @@ public class AAA { |
253 | case EAPOL: | 294 | case EAPOL: |
254 | handleSupplicantPacket(context.inPacket()); | 295 | handleSupplicantPacket(context.inPacket()); |
255 | break; | 296 | break; |
256 | - case IPV4: | ||
257 | - IPv4 ipv4Packet = (IPv4) ethPkt.getPayload(); | ||
258 | - Ip4Address srcIp = Ip4Address.valueOf(ipv4Packet.getSourceAddress()); | ||
259 | - Ip4Address radiusIp4Address = Ip4Address.valueOf(radiusIpAddress); | ||
260 | - if (srcIp.equals(radiusIp4Address) && ipv4Packet.getProtocol() == IPv4.PROTOCOL_UDP) { | ||
261 | - // TODO: check for port as well when it's configurable | ||
262 | - UDP udpPacket = (UDP) ipv4Packet.getPayload(); | ||
263 | - | ||
264 | - byte[] datagram = udpPacket.getPayload().serialize(); | ||
265 | - RADIUS radiusPacket; | ||
266 | - radiusPacket = RADIUS.deserializer().deserialize(datagram, 0, datagram.length); | ||
267 | - handleRadiusPacket(radiusPacket); | ||
268 | - } | ||
269 | - | ||
270 | - break; | ||
271 | default: | 297 | default: |
272 | log.trace("Skipping Ethernet packet type {}", | 298 | log.trace("Skipping Ethernet packet type {}", |
273 | EthType.EtherType.lookup(ethPkt.getEtherType())); | 299 | EthType.EtherType.lookup(ethPkt.getEtherType())); |
274 | } | 300 | } |
275 | - } catch (DeserializationException | StateMachineException e) { | 301 | + } catch (StateMachineException e) { |
276 | log.warn("Unable to process RADIUS packet:", e); | 302 | log.warn("Unable to process RADIUS packet:", e); |
277 | } | 303 | } |
278 | } | 304 | } |
... | @@ -280,23 +306,26 @@ public class AAA { | ... | @@ -280,23 +306,26 @@ public class AAA { |
280 | /** | 306 | /** |
281 | * Creates and initializes common fields of a RADIUS packet. | 307 | * Creates and initializes common fields of a RADIUS packet. |
282 | * | 308 | * |
283 | - * @param identifier RADIUS identifier | 309 | + * @param stateMachine state machine for the request |
284 | * @param eapPacket EAP packet | 310 | * @param eapPacket EAP packet |
285 | * @return RADIUS packet | 311 | * @return RADIUS packet |
286 | */ | 312 | */ |
287 | - private RADIUS getRadiusPayload(byte identifier, EAP eapPacket) { | 313 | + private RADIUS getRadiusPayload(StateMachine stateMachine, byte identifier, EAP eapPacket) { |
288 | RADIUS radiusPayload = | 314 | RADIUS radiusPayload = |
289 | new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST, | 315 | new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST, |
290 | eapPacket.getIdentifier()); | 316 | eapPacket.getIdentifier()); |
317 | + | ||
318 | + // set Request Authenticator in StateMachine | ||
319 | + stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode()); | ||
320 | + | ||
291 | radiusPayload.setIdentifier(identifier); | 321 | radiusPayload.setIdentifier(identifier); |
292 | radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME, | 322 | radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME, |
293 | - eapPacket.getData()); | 323 | + stateMachine.username()); |
294 | 324 | ||
295 | radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP, | 325 | radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP, |
296 | AAA.this.nasIpAddress.getAddress()); | 326 | AAA.this.nasIpAddress.getAddress()); |
297 | 327 | ||
298 | radiusPayload.encapsulateMessage(eapPacket); | 328 | radiusPayload.encapsulateMessage(eapPacket); |
299 | - radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret); | ||
300 | 329 | ||
301 | return radiusPayload; | 330 | return radiusPayload; |
302 | } | 331 | } |
... | @@ -329,13 +358,13 @@ public class AAA { | ... | @@ -329,13 +358,13 @@ public class AAA { |
329 | 358 | ||
330 | //send an EAP Request/Identify to the supplicant | 359 | //send an EAP Request/Identify to the supplicant |
331 | EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.identifier(), EAP.ATTR_IDENTITY, null); | 360 | EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.identifier(), EAP.ATTR_IDENTITY, null); |
332 | - Ethernet eth = buildEapolResponse(srcMAC, MacAddress.valueOf(1L), | 361 | + Ethernet eth = buildEapolResponse(srcMAC, MacAddress.valueOf(nasMacAddress), |
333 | ethPkt.getVlanID(), EAPOL.EAPOL_PACKET, | 362 | ethPkt.getVlanID(), EAPOL.EAPOL_PACKET, |
334 | eapPayload); | 363 | eapPayload); |
335 | stateMachine.setSupplicantAddress(srcMAC); | 364 | stateMachine.setSupplicantAddress(srcMAC); |
336 | stateMachine.setVlanId(ethPkt.getVlanID()); | 365 | stateMachine.setVlanId(ethPkt.getVlanID()); |
337 | 366 | ||
338 | - this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint()); | 367 | + sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint()); |
339 | 368 | ||
340 | break; | 369 | break; |
341 | case EAPOL.EAPOL_PACKET: | 370 | case EAPOL.EAPOL_PACKET: |
... | @@ -350,11 +379,10 @@ public class AAA { | ... | @@ -350,11 +379,10 @@ public class AAA { |
350 | // request id access to RADIUS | 379 | // request id access to RADIUS |
351 | stateMachine.setUsername(eapPacket.getData()); | 380 | stateMachine.setUsername(eapPacket.getData()); |
352 | 381 | ||
353 | - radiusPayload = getRadiusPayload(stateMachine.identifier(), eapPacket); | 382 | + radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket); |
383 | + radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret); | ||
354 | 384 | ||
355 | - // set Request Authenticator in StateMachine | 385 | + sendRADIUSPacket(radiusPayload); |
356 | - stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode()); | ||
357 | - sendRadiusMessage(radiusPayload); | ||
358 | 386 | ||
359 | // change the state to "PENDING" | 387 | // change the state to "PENDING" |
360 | stateMachine.requestAccess(); | 388 | stateMachine.requestAccess(); |
... | @@ -365,22 +393,27 @@ public class AAA { | ... | @@ -365,22 +393,27 @@ public class AAA { |
365 | // machine. | 393 | // machine. |
366 | if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) { | 394 | if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) { |
367 | //send the RADIUS challenge response | 395 | //send the RADIUS challenge response |
368 | - radiusPayload = getRadiusPayload(stateMachine.challengeIdentifier(), eapPacket); | 396 | + radiusPayload = |
397 | + getRadiusPayload(stateMachine, | ||
398 | + stateMachine.identifier(), | ||
399 | + eapPacket); | ||
369 | 400 | ||
370 | radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE, | 401 | radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE, |
371 | stateMachine.challengeState()); | 402 | stateMachine.challengeState()); |
372 | - sendRadiusMessage(radiusPayload); | 403 | + radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret); |
404 | + sendRADIUSPacket(radiusPayload); | ||
373 | } | 405 | } |
374 | break; | 406 | break; |
375 | case EAP.ATTR_TLS: | 407 | case EAP.ATTR_TLS: |
376 | // request id access to RADIUS | 408 | // request id access to RADIUS |
377 | - radiusPayload = getRadiusPayload(stateMachine.identifier(), eapPacket); | 409 | + radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket); |
378 | 410 | ||
379 | radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE, | 411 | radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE, |
380 | stateMachine.challengeState()); | 412 | stateMachine.challengeState()); |
381 | stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode()); | 413 | stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode()); |
382 | 414 | ||
383 | - sendRadiusMessage(radiusPayload); | 415 | + sendRADIUSPacket(radiusPayload); |
416 | + radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret); | ||
384 | // TODO: this gets called on every fragment, should only be called at TLS-Start | 417 | // TODO: this gets called on every fragment, should only be called at TLS-Start |
385 | stateMachine.requestAccess(); | 418 | stateMachine.requestAccess(); |
386 | 419 | ||
... | @@ -392,14 +425,18 @@ public class AAA { | ... | @@ -392,14 +425,18 @@ public class AAA { |
392 | default: | 425 | default: |
393 | log.trace("Skipping EAPOL message {}", eapol.getEapolType()); | 426 | log.trace("Skipping EAPOL message {}", eapol.getEapolType()); |
394 | } | 427 | } |
428 | + | ||
429 | + } | ||
395 | } | 430 | } |
396 | 431 | ||
432 | + class RadiusListener implements Runnable { | ||
433 | + | ||
397 | /** | 434 | /** |
398 | * Handles RADIUS packets. | 435 | * Handles RADIUS packets. |
399 | * | 436 | * |
400 | * @param radiusPacket RADIUS packet coming from the RADIUS server. | 437 | * @param radiusPacket RADIUS packet coming from the RADIUS server. |
401 | */ | 438 | */ |
402 | - private void handleRadiusPacket(RADIUS radiusPacket) throws StateMachineException { | 439 | + protected void handleRadiusPacket(RADIUS radiusPacket) throws StateMachineException { |
403 | StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier()); | 440 | StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier()); |
404 | if (stateMachine == null) { | 441 | if (stateMachine == null) { |
405 | log.error("Invalid session identifier, exiting..."); | 442 | log.error("Invalid session identifier, exiting..."); |
... | @@ -410,13 +447,16 @@ public class AAA { | ... | @@ -410,13 +447,16 @@ public class AAA { |
410 | Ethernet eth; | 447 | Ethernet eth; |
411 | switch (radiusPacket.getCode()) { | 448 | switch (radiusPacket.getCode()) { |
412 | case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE: | 449 | case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE: |
413 | - byte[] challengeState = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE).getValue(); | 450 | + byte[] challengeState = |
451 | + radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE).getValue(); | ||
414 | eapPayload = radiusPacket.decapsulateMessage(); | 452 | eapPayload = radiusPacket.decapsulateMessage(); |
415 | stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState); | 453 | stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState); |
416 | eth = buildEapolResponse(stateMachine.supplicantAddress(), | 454 | eth = buildEapolResponse(stateMachine.supplicantAddress(), |
417 | - MacAddress.valueOf(1L), stateMachine.vlanId(), EAPOL.EAPOL_PACKET, | 455 | + MacAddress.valueOf(nasMacAddress), |
456 | + stateMachine.vlanId(), | ||
457 | + EAPOL.EAPOL_PACKET, | ||
418 | eapPayload); | 458 | eapPayload); |
419 | - this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint()); | 459 | + sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint()); |
420 | break; | 460 | break; |
421 | case RADIUS.RADIUS_CODE_ACCESS_ACCEPT: | 461 | case RADIUS.RADIUS_CODE_ACCESS_ACCEPT: |
422 | //send an EAPOL - Success to the supplicant. | 462 | //send an EAPOL - Success to the supplicant. |
... | @@ -425,9 +465,11 @@ public class AAA { | ... | @@ -425,9 +465,11 @@ public class AAA { |
425 | eapPayload = new EAP(); | 465 | eapPayload = new EAP(); |
426 | eapPayload = (EAP) eapPayload.deserialize(eapMessage, 0, eapMessage.length); | 466 | eapPayload = (EAP) eapPayload.deserialize(eapMessage, 0, eapMessage.length); |
427 | eth = buildEapolResponse(stateMachine.supplicantAddress(), | 467 | eth = buildEapolResponse(stateMachine.supplicantAddress(), |
428 | - MacAddress.valueOf(1L), stateMachine.vlanId(), EAPOL.EAPOL_PACKET, | 468 | + MacAddress.valueOf(nasMacAddress), |
469 | + stateMachine.vlanId(), | ||
470 | + EAPOL.EAPOL_PACKET, | ||
429 | eapPayload); | 471 | eapPayload); |
430 | - this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint()); | 472 | + sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint()); |
431 | 473 | ||
432 | stateMachine.authorizeAccess(); | 474 | stateMachine.authorizeAccess(); |
433 | break; | 475 | break; |
... | @@ -439,58 +481,42 @@ public class AAA { | ... | @@ -439,58 +481,42 @@ public class AAA { |
439 | } | 481 | } |
440 | } | 482 | } |
441 | 483 | ||
442 | - private void sendRadiusMessage(RADIUS radiusMessage) { | ||
443 | - Set<Host> hosts = hostService.getHostsByIp(IpAddress.valueOf(radiusIpAddress)); | ||
444 | - Optional<Host> odst = hosts.stream().filter(h -> h.vlan().toShort() == VlanId.UNTAGGED).findFirst(); | ||
445 | 484 | ||
446 | - Host dst; | 485 | + @Override |
447 | - if (!odst.isPresent()) { | 486 | + public void run() { |
448 | - log.info("Radius server {} is not present", radiusIpAddress); | 487 | + boolean done = false; |
449 | - return; | 488 | + int packetNumber = 1; |
450 | - } else { | ||
451 | - dst = odst.get(); | ||
452 | - } | ||
453 | - | ||
454 | - UDP udp = new UDP(); | ||
455 | - IPv4 ip4Packet = new IPv4(); | ||
456 | - Ethernet ethPkt = new Ethernet(); | ||
457 | - radiusMessage.setParent(udp); | ||
458 | - udp.setDestinationPort(radiusServerPort); | ||
459 | - udp.setSourcePort(radiusServerPort); | ||
460 | - udp.setPayload(radiusMessage); | ||
461 | - udp.setParent(ip4Packet); | ||
462 | - ip4Packet.setSourceAddress(AAA.this.nasIpAddress.getHostAddress()); | ||
463 | - ip4Packet.setDestinationAddress(AAA.this.radiusIpAddress.getHostAddress()); | ||
464 | - ip4Packet.setProtocol(IPv4.PROTOCOL_UDP); | ||
465 | - ip4Packet.setPayload(udp); | ||
466 | - ip4Packet.setParent(ethPkt); | ||
467 | - ethPkt.setDestinationMACAddress(radiusMacAddress); | ||
468 | - ethPkt.setSourceMACAddress(nasMacAddress); | ||
469 | - ethPkt.setEtherType(Ethernet.TYPE_IPV4); | ||
470 | - ethPkt.setPayload(ip4Packet); | ||
471 | - | ||
472 | - TrafficTreatment treatment = DefaultTrafficTreatment.builder() | ||
473 | - .setOutput(PortNumber.portNumber(radiusPort)).build(); | ||
474 | - OutboundPacket packet = new DefaultOutboundPacket(DeviceId.deviceId(radiusSwitch), | ||
475 | - treatment, ByteBuffer.wrap(ethPkt.serialize())); | ||
476 | - packetService.emit(packet); | ||
477 | 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); | ||
478 | } | 509 | } |
479 | 510 | ||
480 | - /** | 511 | + } catch (IOException e) { |
481 | - * Send the ethernet packet to the supplicant. | 512 | + log.info("Socket was closed, exiting listener thread"); |
482 | - * | 513 | + done = true; |
483 | - * @param ethernetPkt the ethernet packet | 514 | + } |
484 | - * @param connectPoint the connect point to send out | ||
485 | - */ | ||
486 | - private void sendPacketToSupplicant(Ethernet ethernetPkt, ConnectPoint connectPoint) { | ||
487 | - TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build(); | ||
488 | - OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(), | ||
489 | - treatment, ByteBuffer.wrap(ethernetPkt.serialize())); | ||
490 | - packetService.emit(packet); | ||
491 | } | 515 | } |
492 | - | ||
493 | } | 516 | } |
517 | + } | ||
518 | + | ||
519 | + RadiusListener radiusListener = new RadiusListener(); | ||
494 | 520 | ||
495 | private class InternalConfigListener implements NetworkConfigListener { | 521 | private class InternalConfigListener implements NetworkConfigListener { |
496 | 522 | ... | ... |
... | @@ -37,13 +37,13 @@ public class AAAConfig extends Config<ApplicationId> { | ... | @@ -37,13 +37,13 @@ public class AAAConfig extends Config<ApplicationId> { |
37 | private static final String RADIUS_PORT = "radiusPort"; | 37 | private static final String RADIUS_PORT = "radiusPort"; |
38 | 38 | ||
39 | // RADIUS server IP address | 39 | // RADIUS server IP address |
40 | - protected static final String DEFAULT_RADIUS_IP = "192.168.1.10"; | 40 | + protected static final String DEFAULT_RADIUS_IP = "10.128.10.4"; |
41 | 41 | ||
42 | // RADIUS MAC address | 42 | // RADIUS MAC address |
43 | protected static final String DEFAULT_RADIUS_MAC = "00:00:00:00:01:10"; | 43 | protected static final String DEFAULT_RADIUS_MAC = "00:00:00:00:01:10"; |
44 | 44 | ||
45 | // NAS IP address | 45 | // NAS IP address |
46 | - protected static final String DEFAULT_NAS_IP = "192.168.1.11"; | 46 | + protected static final String DEFAULT_NAS_IP = "10.128.9.244"; |
47 | 47 | ||
48 | // NAS MAC address | 48 | // NAS MAC address |
49 | protected static final String DEFAULT_NAS_MAC = "00:00:00:00:10:01"; | 49 | protected static final String DEFAULT_NAS_MAC = "00:00:00:00:10:01"; | ... | ... |
1 | +/* | ||
2 | + * Copyright 2014 Open Networking Laboratory | ||
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 | + */ | ||
16 | +package org.onosproject.aaa; | ||
17 | + | ||
18 | +import org.junit.Before; | ||
19 | +import org.junit.Ignore; | ||
20 | +import org.junit.Test; | ||
21 | +import org.onlab.packet.EAP; | ||
22 | +import org.onlab.packet.EAPOL; | ||
23 | +import org.onlab.packet.Ethernet; | ||
24 | +import org.onosproject.core.CoreServiceAdapter; | ||
25 | +import org.onosproject.net.config.Config; | ||
26 | +import org.onosproject.net.config.NetworkConfigRegistryAdapter; | ||
27 | + | ||
28 | +import static org.hamcrest.Matchers.is; | ||
29 | +import static org.hamcrest.Matchers.notNullValue; | ||
30 | +import static org.junit.Assert.assertThat; | ||
31 | + | ||
32 | +/** | ||
33 | + * Set of tests of the ONOS application component. These use an existing RADIUS | ||
34 | + * server and sends live packets over the network to it. | ||
35 | + */ | ||
36 | +@Ignore ("This should not be run as part of the standard build") | ||
37 | +public class AAAIntegrationTest extends AAATestBase { | ||
38 | + | ||
39 | + private AAA aaa; | ||
40 | + | ||
41 | + /** | ||
42 | + * Mocks the network config registry. | ||
43 | + */ | ||
44 | + @SuppressWarnings("unchecked") | ||
45 | + static final class TestNetworkConfigRegistry | ||
46 | + extends NetworkConfigRegistryAdapter { | ||
47 | + @Override | ||
48 | + public <S, C extends Config<S>> C getConfig(S subject, Class<C> configClass) { | ||
49 | + return (C) new AAAConfig(); | ||
50 | + } | ||
51 | + } | ||
52 | + | ||
53 | + /** | ||
54 | + * Sets up the services required by the AAA application. | ||
55 | + */ | ||
56 | + @Before | ||
57 | + public void setUp() { | ||
58 | + aaa = new AAA(); | ||
59 | + aaa.netCfgService = new TestNetworkConfigRegistry(); | ||
60 | + aaa.coreService = new CoreServiceAdapter(); | ||
61 | + aaa.packetService = new MockPacketService(); | ||
62 | + aaa.activate(); | ||
63 | + } | ||
64 | + | ||
65 | + /** | ||
66 | + * Fetches the sent packet at the given index. The requested packet | ||
67 | + * must be the last packet on the list. | ||
68 | + * | ||
69 | + * @param index index into sent packets array | ||
70 | + * @return packet | ||
71 | + */ | ||
72 | + private Ethernet fetchPacket(int index) { | ||
73 | + for (int iteration = 0; iteration < 20; iteration++) { | ||
74 | + if (savedPackets.size() > index) { | ||
75 | + return (Ethernet) savedPackets.get(index); | ||
76 | + } else { | ||
77 | + try { | ||
78 | + Thread.sleep(250); | ||
79 | + } catch (Exception ex) { | ||
80 | + return null; | ||
81 | + } | ||
82 | + } | ||
83 | + } | ||
84 | + return null; | ||
85 | + } | ||
86 | + | ||
87 | + /** | ||
88 | + * Tests the authentication path through the AAA application by sending | ||
89 | + * packets to the RADIUS server and checking the state machine | ||
90 | + * transitions. | ||
91 | + * | ||
92 | + * @throws Exception when an unhandled error occurs | ||
93 | + */ | ||
94 | + @Test | ||
95 | + public void testAuthentication() throws Exception { | ||
96 | + | ||
97 | + // (1) Supplicant start up | ||
98 | + | ||
99 | + Ethernet startPacket = constructSupplicantStartPacket(); | ||
100 | + sendPacket(startPacket); | ||
101 | + | ||
102 | + Ethernet responsePacket = fetchPacket(0); | ||
103 | + assertThat(responsePacket, notNullValue()); | ||
104 | + checkRadiusPacket(aaa, responsePacket, EAP.REQUEST); | ||
105 | + | ||
106 | + // (2) Supplicant identify | ||
107 | + | ||
108 | + Ethernet identifyPacket = constructSupplicantIdentifyPacket(null, EAP.ATTR_IDENTITY, (byte) 1, null); | ||
109 | + sendPacket(identifyPacket); | ||
110 | + | ||
111 | + // State machine should have been created by now | ||
112 | + | ||
113 | + StateMachine stateMachine = | ||
114 | + StateMachine.lookupStateMachineBySessionId(SESSION_ID); | ||
115 | + assertThat(stateMachine, notNullValue()); | ||
116 | + assertThat(stateMachine.state(), is(StateMachine.STATE_PENDING)); | ||
117 | + | ||
118 | + // (3) RADIUS MD5 challenge | ||
119 | + | ||
120 | + Ethernet radiusChallengeMD5Packet = fetchPacket(1); | ||
121 | + assertThat(radiusChallengeMD5Packet, notNullValue()); | ||
122 | + checkRadiusPacket(aaa, radiusChallengeMD5Packet, EAP.REQUEST); | ||
123 | + | ||
124 | + | ||
125 | + // (4) Supplicant MD5 response | ||
126 | + | ||
127 | + Ethernet md5RadiusPacket = | ||
128 | + constructSupplicantIdentifyPacket(stateMachine, | ||
129 | + EAP.ATTR_MD5, | ||
130 | + stateMachine.challengeIdentifier(), | ||
131 | + radiusChallengeMD5Packet); | ||
132 | + sendPacket(md5RadiusPacket); | ||
133 | + | ||
134 | + | ||
135 | + // (5) RADIUS Success | ||
136 | + | ||
137 | + Ethernet successRadiusPacket = fetchPacket(2); | ||
138 | + assertThat(successRadiusPacket, notNullValue()); | ||
139 | + EAPOL successEAPOL = (EAPOL) successRadiusPacket.getPayload(); | ||
140 | + EAP successEAP = (EAP) successEAPOL.getPayload(); | ||
141 | + assertThat(successEAP.getCode(), is(EAP.SUCCESS)); | ||
142 | + | ||
143 | + // State machine should be in authorized state | ||
144 | + | ||
145 | + assertThat(stateMachine, notNullValue()); | ||
146 | + assertThat(stateMachine.state(), is(StateMachine.STATE_AUTHORIZED)); | ||
147 | + | ||
148 | + } | ||
149 | + | ||
150 | +} | ||
151 | + |
... | @@ -15,160 +15,57 @@ | ... | @@ -15,160 +15,57 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.aaa; | 16 | package org.onosproject.aaa; |
17 | 17 | ||
18 | -import java.nio.ByteBuffer; | 18 | +import java.net.InetAddress; |
19 | -import java.util.LinkedList; | 19 | +import java.net.UnknownHostException; |
20 | -import java.util.List; | ||
21 | -import java.util.Set; | ||
22 | 20 | ||
23 | import org.junit.After; | 21 | import org.junit.After; |
24 | import org.junit.Before; | 22 | import org.junit.Before; |
25 | import org.junit.Test; | 23 | import org.junit.Test; |
26 | -import org.onlab.packet.Data; | 24 | +import org.onlab.packet.BasePacket; |
27 | import org.onlab.packet.DeserializationException; | 25 | import org.onlab.packet.DeserializationException; |
28 | import org.onlab.packet.EAP; | 26 | import org.onlab.packet.EAP; |
29 | -import org.onlab.packet.EAPOL; | ||
30 | -import org.onlab.packet.EthType; | ||
31 | import org.onlab.packet.Ethernet; | 27 | import org.onlab.packet.Ethernet; |
32 | -import org.onlab.packet.IPv4; | ||
33 | import org.onlab.packet.IpAddress; | 28 | import org.onlab.packet.IpAddress; |
34 | -import org.onlab.packet.MacAddress; | ||
35 | import org.onlab.packet.RADIUS; | 29 | import org.onlab.packet.RADIUS; |
36 | import org.onlab.packet.RADIUSAttribute; | 30 | import org.onlab.packet.RADIUSAttribute; |
37 | -import org.onlab.packet.UDP; | ||
38 | -import org.onlab.packet.VlanId; | ||
39 | import org.onosproject.core.CoreServiceAdapter; | 31 | import org.onosproject.core.CoreServiceAdapter; |
40 | -import org.onosproject.net.Annotations; | ||
41 | -import org.onosproject.net.Host; | ||
42 | -import org.onosproject.net.HostId; | ||
43 | -import org.onosproject.net.HostLocation; | ||
44 | import org.onosproject.net.config.Config; | 32 | import org.onosproject.net.config.Config; |
45 | import org.onosproject.net.config.NetworkConfigRegistryAdapter; | 33 | import org.onosproject.net.config.NetworkConfigRegistryAdapter; |
46 | -import org.onosproject.net.host.HostServiceAdapter; | ||
47 | -import org.onosproject.net.packet.DefaultInboundPacket; | ||
48 | -import org.onosproject.net.packet.DefaultPacketContext; | ||
49 | -import org.onosproject.net.packet.InboundPacket; | ||
50 | -import org.onosproject.net.packet.OutboundPacket; | ||
51 | -import org.onosproject.net.packet.PacketContext; | ||
52 | -import org.onosproject.net.packet.PacketProcessor; | ||
53 | -import org.onosproject.net.packet.PacketServiceAdapter; | ||
54 | -import org.onosproject.net.provider.ProviderId; | ||
55 | 34 | ||
56 | import com.google.common.base.Charsets; | 35 | import com.google.common.base.Charsets; |
57 | -import com.google.common.collect.ImmutableSet; | ||
58 | 36 | ||
59 | -import static org.hamcrest.Matchers.instanceOf; | ||
60 | import static org.hamcrest.Matchers.is; | 37 | import static org.hamcrest.Matchers.is; |
61 | import static org.hamcrest.Matchers.notNullValue; | 38 | import static org.hamcrest.Matchers.notNullValue; |
62 | import static org.junit.Assert.assertThat; | 39 | import static org.junit.Assert.assertThat; |
63 | -import static org.junit.Assert.fail; | ||
64 | -import static org.onosproject.net.NetTestTools.connectPoint; | ||
65 | 40 | ||
66 | /** | 41 | /** |
67 | * Set of tests of the ONOS application component. | 42 | * Set of tests of the ONOS application component. |
68 | */ | 43 | */ |
69 | -public class AAATest { | 44 | +public class AAATest extends AAATestBase { |
70 | 45 | ||
71 | - MacAddress clientMac = MacAddress.valueOf("1a:1a:1a:1a:1a:1a"); | 46 | + static final String BAD_IP_ADDRESS = "198.51.100.0"; |
72 | - MacAddress serverMac = MacAddress.valueOf("2a:2a:2a:2a:2a:2a"); | ||
73 | 47 | ||
74 | - PacketProcessor packetProcessor; | ||
75 | private AAA aaa; | 48 | private AAA aaa; |
76 | - List<Ethernet> savedPackets = new LinkedList<>(); | ||
77 | 49 | ||
78 | - /** | 50 | + class AAAWithoutRadiusServer extends AAA { |
79 | - * Saves the given packet onto the saved packets list. | 51 | + protected void sendRADIUSPacket(RADIUS radiusPacket) { |
80 | - * | 52 | + savePacket(radiusPacket); |
81 | - * @param eth packet to save | ||
82 | - */ | ||
83 | - private void savePacket(Ethernet eth) { | ||
84 | - savedPackets.add(eth); | ||
85 | - } | ||
86 | - | ||
87 | - /** | ||
88 | - * Keeps a reference to the PacketProcessor and saves the OutboundPackets. | ||
89 | - */ | ||
90 | - private class MockPacketService extends PacketServiceAdapter { | ||
91 | - | ||
92 | - @Override | ||
93 | - public void addProcessor(PacketProcessor processor, int priority) { | ||
94 | - packetProcessor = processor; | ||
95 | - } | ||
96 | - | ||
97 | - @Override | ||
98 | - public void emit(OutboundPacket packet) { | ||
99 | - try { | ||
100 | - Ethernet eth = Ethernet.deserializer().deserialize(packet.data().array(), | ||
101 | - 0, packet.data().array().length); | ||
102 | - savePacket(eth); | ||
103 | - } catch (Exception e) { | ||
104 | - fail(e.getMessage()); | ||
105 | - } | ||
106 | - } | ||
107 | - } | ||
108 | - | ||
109 | - /** | ||
110 | - * Mocks the DefaultPacketContext. | ||
111 | - */ | ||
112 | - private final class TestPacketContext extends DefaultPacketContext { | ||
113 | - | ||
114 | - private TestPacketContext(long time, InboundPacket inPkt, | ||
115 | - OutboundPacket outPkt, boolean block) { | ||
116 | - super(time, inPkt, outPkt, block); | ||
117 | - } | ||
118 | - | ||
119 | - @Override | ||
120 | - public void send() { | ||
121 | - // We don't send anything out. | ||
122 | } | 53 | } |
123 | } | 54 | } |
124 | 55 | ||
125 | /** | 56 | /** |
126 | - * Mocks a host to allow locating the Radius server. | 57 | + * Mocks the AAAConfig class to force usage of an unroutable address for the |
58 | + * RADIUS server. | ||
127 | */ | 59 | */ |
128 | - private static final class MockHost implements Host { | 60 | + static class MockAAAConfig extends AAAConfig { |
129 | @Override | 61 | @Override |
130 | - public HostId id() { | 62 | + public InetAddress radiusIp() { |
131 | - return null; | 63 | + try { |
132 | - } | 64 | + return InetAddress.getByName(BAD_IP_ADDRESS); |
133 | - | 65 | + } catch (UnknownHostException ex) { |
134 | - @Override | 66 | + // can't happen |
135 | - public MacAddress mac() { | 67 | + throw new IllegalStateException(ex); |
136 | - return null; | ||
137 | - } | ||
138 | - | ||
139 | - @Override | ||
140 | - public VlanId vlan() { | ||
141 | - return VlanId.vlanId(VlanId.UNTAGGED); | ||
142 | - } | ||
143 | - | ||
144 | - @Override | ||
145 | - public Set<IpAddress> ipAddresses() { | ||
146 | - return null; | ||
147 | - } | ||
148 | - | ||
149 | - @Override | ||
150 | - public HostLocation location() { | ||
151 | - return null; | ||
152 | } | 68 | } |
153 | - | ||
154 | - @Override | ||
155 | - public Annotations annotations() { | ||
156 | - return null; | ||
157 | - } | ||
158 | - | ||
159 | - @Override | ||
160 | - public ProviderId providerId() { | ||
161 | - return null; | ||
162 | - } | ||
163 | - } | ||
164 | - | ||
165 | - /** | ||
166 | - * Mocks the Host service. | ||
167 | - */ | ||
168 | - private static final class MockHostService extends HostServiceAdapter { | ||
169 | - @Override | ||
170 | - public Set<Host> getHostsByIp(IpAddress ip) { | ||
171 | - return ImmutableSet.of(new MockHost()); | ||
172 | } | 69 | } |
173 | } | 70 | } |
174 | 71 | ||
... | @@ -180,80 +77,9 @@ public class AAATest { | ... | @@ -180,80 +77,9 @@ public class AAATest { |
180 | extends NetworkConfigRegistryAdapter { | 77 | extends NetworkConfigRegistryAdapter { |
181 | @Override | 78 | @Override |
182 | public <S, C extends Config<S>> C getConfig(S subject, Class<C> configClass) { | 79 | public <S, C extends Config<S>> C getConfig(S subject, Class<C> configClass) { |
183 | - return (C) new AAAConfig(); | 80 | + AAAConfig aaaConfig = new MockAAAConfig(); |
184 | - } | 81 | + return (C) aaaConfig; |
185 | - } | ||
186 | - | ||
187 | - /** | ||
188 | - * Sends an Ethernet packet to the process method of the Packet Processor. | ||
189 | - * | ||
190 | - * @param reply Ethernet packet | ||
191 | - */ | ||
192 | - private void sendPacket(Ethernet reply) { | ||
193 | - final ByteBuffer byteBuffer = ByteBuffer.wrap(reply.serialize()); | ||
194 | - InboundPacket inPacket = new DefaultInboundPacket(connectPoint("1", 1), | ||
195 | - reply, | ||
196 | - byteBuffer); | ||
197 | - | ||
198 | - PacketContext context = new TestPacketContext(127L, inPacket, null, false); | ||
199 | - packetProcessor.process(context); | ||
200 | - } | ||
201 | - | ||
202 | - /** | ||
203 | - * Constructs an Ethernet packet containing a EAPOL_START Payload. | ||
204 | - * | ||
205 | - * @return Ethernet packet | ||
206 | - */ | ||
207 | - private Ethernet constructSupplicantStartPacket() { | ||
208 | - Ethernet eth = new Ethernet(); | ||
209 | - eth.setDestinationMACAddress(clientMac.toBytes()); | ||
210 | - eth.setSourceMACAddress(serverMac.toBytes()); | ||
211 | - eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort()); | ||
212 | - eth.setVlanID((short) 2); | ||
213 | - | ||
214 | - EAP eap = new EAP(EAPOL.EAPOL_START, (byte) 1, EAPOL.EAPOL_START, null); | ||
215 | - | ||
216 | - //eapol header | ||
217 | - EAPOL eapol = new EAPOL(); | ||
218 | - eapol.setEapolType(EAPOL.EAPOL_START); | ||
219 | - eapol.setPacketLength(eap.getLength()); | ||
220 | - | ||
221 | - //eap part | ||
222 | - eapol.setPayload(eap); | ||
223 | - | ||
224 | - eth.setPayload(eapol); | ||
225 | - eth.setPad(true); | ||
226 | - return eth; | ||
227 | } | 82 | } |
228 | - | ||
229 | - /** | ||
230 | - * Constructs an Ethernet packet containing identification payload. | ||
231 | - * | ||
232 | - * @return Ethernet packet | ||
233 | - */ | ||
234 | - private Ethernet constructSupplicantIdentifyPacket(byte type) { | ||
235 | - Ethernet eth = new Ethernet(); | ||
236 | - eth.setDestinationMACAddress(clientMac.toBytes()); | ||
237 | - eth.setSourceMACAddress(serverMac.toBytes()); | ||
238 | - eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort()); | ||
239 | - eth.setVlanID((short) 2); | ||
240 | - | ||
241 | - String username = "user"; | ||
242 | - EAP eap = new EAP(EAP.REQUEST, (byte) 1, type, | ||
243 | - username.getBytes(Charsets.US_ASCII)); | ||
244 | - eap.setIdentifier((byte) 1); | ||
245 | - | ||
246 | - // eapol header | ||
247 | - EAPOL eapol = new EAPOL(); | ||
248 | - eapol.setEapolType(EAPOL.EAPOL_PACKET); | ||
249 | - eapol.setPacketLength(eap.getLength()); | ||
250 | - | ||
251 | - // eap part | ||
252 | - eapol.setPayload(eap); | ||
253 | - | ||
254 | - eth.setPayload(eapol); | ||
255 | - eth.setPad(true); | ||
256 | - return eth; | ||
257 | } | 83 | } |
258 | 84 | ||
259 | /** | 85 | /** |
... | @@ -264,18 +90,9 @@ public class AAATest { | ... | @@ -264,18 +90,9 @@ public class AAATest { |
264 | * @param challengeType type to use in challenge packet | 90 | * @param challengeType type to use in challenge packet |
265 | * @return Ethernet packet | 91 | * @return Ethernet packet |
266 | */ | 92 | */ |
267 | - private Ethernet constructRADIUSCodeAccessChallengePacket(byte challengeCode, byte challengeType) { | 93 | + private RADIUS constructRADIUSCodeAccessChallengePacket(byte challengeCode, byte challengeType) { |
268 | - Ethernet eth = new Ethernet(); | ||
269 | - eth.setDestinationMACAddress(clientMac.toBytes()); | ||
270 | - eth.setSourceMACAddress(serverMac.toBytes()); | ||
271 | - eth.setEtherType(EthType.EtherType.IPV4.ethType().toShort()); | ||
272 | - eth.setVlanID((short) 2); | ||
273 | - | ||
274 | - IPv4 ipv4 = new IPv4(); | ||
275 | - ipv4.setProtocol(IPv4.PROTOCOL_UDP); | ||
276 | - ipv4.setSourceAddress(aaa.radiusIpAddress.getHostAddress()); | ||
277 | 94 | ||
278 | - String challenge = "1234"; | 95 | + String challenge = "12345678901234567"; |
279 | 96 | ||
280 | EAP eap = new EAP(challengeType, (byte) 1, challengeType, | 97 | EAP eap = new EAP(challengeType, (byte) 1, challengeType, |
281 | challenge.getBytes(Charsets.US_ASCII)); | 98 | challenge.getBytes(Charsets.US_ASCII)); |
... | @@ -291,13 +108,7 @@ public class AAATest { | ... | @@ -291,13 +108,7 @@ public class AAATest { |
291 | radius.setAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE, | 108 | radius.setAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE, |
292 | eap.serialize()); | 109 | eap.serialize()); |
293 | 110 | ||
294 | - UDP udp = new UDP(); | 111 | + return radius; |
295 | - udp.setPayload(radius); | ||
296 | - ipv4.setPayload(udp); | ||
297 | - | ||
298 | - eth.setPayload(ipv4); | ||
299 | - eth.setPad(true); | ||
300 | - return eth; | ||
301 | } | 112 | } |
302 | 113 | ||
303 | /** | 114 | /** |
... | @@ -305,11 +116,10 @@ public class AAATest { | ... | @@ -305,11 +116,10 @@ public class AAATest { |
305 | */ | 116 | */ |
306 | @Before | 117 | @Before |
307 | public void setUp() { | 118 | public void setUp() { |
308 | - aaa = new AAA(); | 119 | + aaa = new AAAWithoutRadiusServer(); |
309 | aaa.netCfgService = new TestNetworkConfigRegistry(); | 120 | aaa.netCfgService = new TestNetworkConfigRegistry(); |
310 | aaa.coreService = new CoreServiceAdapter(); | 121 | aaa.coreService = new CoreServiceAdapter(); |
311 | aaa.packetService = new MockPacketService(); | 122 | aaa.packetService = new MockPacketService(); |
312 | - aaa.hostService = new MockHostService(); | ||
313 | aaa.activate(); | 123 | aaa.activate(); |
314 | } | 124 | } |
315 | 125 | ||
... | @@ -324,60 +134,16 @@ public class AAATest { | ... | @@ -324,60 +134,16 @@ public class AAATest { |
324 | /** | 134 | /** |
325 | * Extracts the RADIUS packet from a packet sent by the supplicant. | 135 | * Extracts the RADIUS packet from a packet sent by the supplicant. |
326 | * | 136 | * |
327 | - * @param supplicantPacket packet sent by the supplicant | 137 | + * @param radius RADIUS packet sent by the supplicant |
328 | - * @return RADIUS packet | ||
329 | * @throws DeserializationException if deserialization of the packet contents | 138 | * @throws DeserializationException if deserialization of the packet contents |
330 | * fails. | 139 | * fails. |
331 | */ | 140 | */ |
332 | - private RADIUS checkAndFetchRADIUSPacketFromSupplicant(Ethernet supplicantPacket) | 141 | + private void checkRADIUSPacketFromSupplicant(RADIUS radius) |
333 | throws DeserializationException { | 142 | throws DeserializationException { |
334 | - assertThat(supplicantPacket, notNullValue()); | ||
335 | - assertThat(supplicantPacket.getVlanID(), is(VlanId.UNTAGGED)); | ||
336 | - assertThat(supplicantPacket.getSourceMAC().toString(), is(aaa.nasMacAddress)); | ||
337 | - assertThat(supplicantPacket.getDestinationMAC().toString(), is(aaa.radiusMacAddress)); | ||
338 | - | ||
339 | - assertThat(supplicantPacket.getPayload(), instanceOf(IPv4.class)); | ||
340 | - IPv4 ipv4 = (IPv4) supplicantPacket.getPayload(); | ||
341 | - assertThat(ipv4, notNullValue()); | ||
342 | - assertThat(IpAddress.valueOf(ipv4.getSourceAddress()).toString(), | ||
343 | - is(aaa.nasIpAddress.getHostAddress())); | ||
344 | - assertThat(IpAddress.valueOf(ipv4.getDestinationAddress()).toString(), | ||
345 | - is(aaa.radiusIpAddress.getHostAddress())); | ||
346 | - | ||
347 | - assertThat(ipv4.getPayload(), instanceOf(UDP.class)); | ||
348 | - UDP udp = (UDP) ipv4.getPayload(); | ||
349 | - assertThat(udp, notNullValue()); | ||
350 | - | ||
351 | - assertThat(udp.getPayload(), instanceOf(Data.class)); | ||
352 | - Data data = (Data) udp.getPayload(); | ||
353 | - RADIUS radius = RADIUS.deserializer() | ||
354 | - .deserialize(data.getData(), 0, data.getData().length); | ||
355 | assertThat(radius, notNullValue()); | 143 | assertThat(radius, notNullValue()); |
356 | - return radius; | ||
357 | - } | ||
358 | - | ||
359 | - /** | ||
360 | - * Checks the contents of a RADIUS packet being sent to the RADIUS server. | ||
361 | - * | ||
362 | - * @param radiusPacket packet to check | ||
363 | - * @param code expected code | ||
364 | - */ | ||
365 | - private void checkRadiusPacket(Ethernet radiusPacket, byte code) { | ||
366 | - assertThat(radiusPacket.getVlanID(), is((short) 2)); | ||
367 | - | ||
368 | - // TODO: These address values seem wrong, but are produced by the current AAA implementation | ||
369 | - assertThat(radiusPacket.getSourceMAC(), is(MacAddress.valueOf(1L))); | ||
370 | - assertThat(radiusPacket.getDestinationMAC(), is(serverMac)); | ||
371 | 144 | ||
372 | - assertThat(radiusPacket.getPayload(), instanceOf(EAPOL.class)); | 145 | + EAP eap = radius.decapsulateMessage(); |
373 | - EAPOL eapol = (EAPOL) radiusPacket.getPayload(); | ||
374 | - assertThat(eapol, notNullValue()); | ||
375 | - | ||
376 | - assertThat(eapol.getEapolType(), is(EAPOL.EAPOL_PACKET)); | ||
377 | - assertThat(eapol.getPayload(), instanceOf(EAP.class)); | ||
378 | - EAP eap = (EAP) eapol.getPayload(); | ||
379 | assertThat(eap, notNullValue()); | 146 | assertThat(eap, notNullValue()); |
380 | - assertThat(eap.getCode(), is(code)); | ||
381 | } | 147 | } |
382 | 148 | ||
383 | /** | 149 | /** |
... | @@ -387,11 +153,10 @@ public class AAATest { | ... | @@ -387,11 +153,10 @@ public class AAATest { |
387 | * @param index index into sent packets array | 153 | * @param index index into sent packets array |
388 | * @return packet | 154 | * @return packet |
389 | */ | 155 | */ |
390 | - private Ethernet fetchPacket(int index) { | 156 | + private BasePacket fetchPacket(int index) { |
391 | - assertThat(savedPackets.size(), is(index + 1)); | 157 | + BasePacket packet = savedPackets.get(index); |
392 | - Ethernet eth = savedPackets.get(index); | 158 | + assertThat(packet, notNullValue()); |
393 | - assertThat(eth, notNullValue()); | 159 | + return packet; |
394 | - return eth; | ||
395 | } | 160 | } |
396 | 161 | ||
397 | /** | 162 | /** |
... | @@ -400,61 +165,64 @@ public class AAATest { | ... | @@ -400,61 +165,64 @@ public class AAATest { |
400 | * @throws DeserializationException if packed deserialization fails. | 165 | * @throws DeserializationException if packed deserialization fails. |
401 | */ | 166 | */ |
402 | @Test | 167 | @Test |
403 | - public void testAuthentication() throws DeserializationException { | 168 | + public void testAuthentication() throws Exception { |
404 | - | ||
405 | - // Our session id will be the device ID ("of:1") with the port ("1") concatenated | ||
406 | - String sessionId = "of:11"; | ||
407 | 169 | ||
408 | // (1) Supplicant start up | 170 | // (1) Supplicant start up |
409 | 171 | ||
410 | Ethernet startPacket = constructSupplicantStartPacket(); | 172 | Ethernet startPacket = constructSupplicantStartPacket(); |
411 | sendPacket(startPacket); | 173 | sendPacket(startPacket); |
412 | 174 | ||
413 | - Ethernet responsePacket = fetchPacket(0); | 175 | + Ethernet responsePacket = (Ethernet) fetchPacket(0); |
414 | - checkRadiusPacket(responsePacket, EAP.ATTR_IDENTITY); | 176 | + checkRadiusPacket(aaa, responsePacket, EAP.ATTR_IDENTITY); |
415 | 177 | ||
416 | // (2) Supplicant identify | 178 | // (2) Supplicant identify |
417 | 179 | ||
418 | - Ethernet identifyPacket = constructSupplicantIdentifyPacket(EAP.ATTR_IDENTITY); | 180 | + Ethernet identifyPacket = constructSupplicantIdentifyPacket(null, EAP.ATTR_IDENTITY, (byte) 1, null); |
419 | sendPacket(identifyPacket); | 181 | sendPacket(identifyPacket); |
420 | 182 | ||
421 | - Ethernet radiusIdentifyPacket = fetchPacket(1); | 183 | + RADIUS radiusIdentifyPacket = (RADIUS) fetchPacket(1); |
184 | + | ||
185 | + checkRADIUSPacketFromSupplicant(radiusIdentifyPacket); | ||
422 | 186 | ||
423 | - RADIUS radiusAccessRequest = checkAndFetchRADIUSPacketFromSupplicant(radiusIdentifyPacket); | 187 | + assertThat(radiusIdentifyPacket.getCode(), is(RADIUS.RADIUS_CODE_ACCESS_REQUEST)); |
424 | - assertThat(radiusAccessRequest, notNullValue()); | 188 | + assertThat(new String(radiusIdentifyPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME).getValue()), |
425 | - assertThat(radiusAccessRequest.getCode(), is(RADIUS.RADIUS_CODE_ACCESS_REQUEST)); | 189 | + is("testuser")); |
426 | - assertThat(new String(radiusAccessRequest.getAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME).getValue()), | ||
427 | - is("user")); | ||
428 | 190 | ||
429 | IpAddress nasIp = | 191 | IpAddress nasIp = |
430 | IpAddress.valueOf(IpAddress.Version.INET, | 192 | IpAddress.valueOf(IpAddress.Version.INET, |
431 | - radiusAccessRequest.getAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP) | 193 | + radiusIdentifyPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP) |
432 | .getValue()); | 194 | .getValue()); |
433 | assertThat(nasIp.toString(), is(aaa.nasIpAddress.getHostAddress())); | 195 | assertThat(nasIp.toString(), is(aaa.nasIpAddress.getHostAddress())); |
434 | 196 | ||
435 | // State machine should have been created by now | 197 | // State machine should have been created by now |
436 | 198 | ||
437 | StateMachine stateMachine = | 199 | StateMachine stateMachine = |
438 | - StateMachine.lookupStateMachineBySessionId(sessionId); | 200 | + StateMachine.lookupStateMachineBySessionId(SESSION_ID); |
439 | assertThat(stateMachine, notNullValue()); | 201 | assertThat(stateMachine, notNullValue()); |
440 | assertThat(stateMachine.state(), is(StateMachine.STATE_PENDING)); | 202 | assertThat(stateMachine.state(), is(StateMachine.STATE_PENDING)); |
441 | 203 | ||
442 | // (3) RADIUS MD5 challenge | 204 | // (3) RADIUS MD5 challenge |
443 | 205 | ||
444 | - Ethernet radiusCodeAccessChallengePacket = | 206 | + RADIUS radiusCodeAccessChallengePacket = |
445 | constructRADIUSCodeAccessChallengePacket(RADIUS.RADIUS_CODE_ACCESS_CHALLENGE, EAP.ATTR_MD5); | 207 | constructRADIUSCodeAccessChallengePacket(RADIUS.RADIUS_CODE_ACCESS_CHALLENGE, EAP.ATTR_MD5); |
446 | - sendPacket(radiusCodeAccessChallengePacket); | 208 | + aaa.radiusListener.handleRadiusPacket(radiusCodeAccessChallengePacket); |
447 | 209 | ||
448 | - Ethernet radiusChallengeMD5Packet = fetchPacket(2); | 210 | + Ethernet radiusChallengeMD5Packet = (Ethernet) fetchPacket(2); |
449 | - checkRadiusPacket(radiusChallengeMD5Packet, EAP.ATTR_MD5); | 211 | + checkRadiusPacket(aaa, radiusChallengeMD5Packet, EAP.ATTR_MD5); |
450 | 212 | ||
451 | // (4) Supplicant MD5 response | 213 | // (4) Supplicant MD5 response |
452 | 214 | ||
453 | - Ethernet md5RadiusPacket = constructSupplicantIdentifyPacket(EAP.ATTR_MD5); | 215 | + Ethernet md5RadiusPacket = |
216 | + constructSupplicantIdentifyPacket(stateMachine, | ||
217 | + EAP.ATTR_MD5, | ||
218 | + stateMachine.challengeIdentifier(), | ||
219 | + radiusChallengeMD5Packet); | ||
454 | sendPacket(md5RadiusPacket); | 220 | sendPacket(md5RadiusPacket); |
455 | - Ethernet supplicantMD5ResponsePacket = fetchPacket(3); | 221 | + |
456 | - RADIUS responseMd5RadiusPacket = checkAndFetchRADIUSPacketFromSupplicant(supplicantMD5ResponsePacket); | 222 | + RADIUS responseMd5RadiusPacket = (RADIUS) fetchPacket(3); |
457 | - assertThat(responseMd5RadiusPacket.getIdentifier(), is((byte) 1)); | 223 | + |
224 | + checkRADIUSPacketFromSupplicant(responseMd5RadiusPacket); | ||
225 | + assertThat(responseMd5RadiusPacket.getIdentifier(), is((byte) 0)); | ||
458 | assertThat(responseMd5RadiusPacket.getCode(), is(RADIUS.RADIUS_CODE_ACCESS_REQUEST)); | 226 | assertThat(responseMd5RadiusPacket.getCode(), is(RADIUS.RADIUS_CODE_ACCESS_REQUEST)); |
459 | 227 | ||
460 | // State machine should be in pending state | 228 | // State machine should be in pending state |
... | @@ -462,37 +230,20 @@ public class AAATest { | ... | @@ -462,37 +230,20 @@ public class AAATest { |
462 | assertThat(stateMachine, notNullValue()); | 230 | assertThat(stateMachine, notNullValue()); |
463 | assertThat(stateMachine.state(), is(StateMachine.STATE_PENDING)); | 231 | assertThat(stateMachine.state(), is(StateMachine.STATE_PENDING)); |
464 | 232 | ||
465 | - // (5) RADIUS TLS Challenge | 233 | + // (5) RADIUS Success |
466 | - | ||
467 | - Ethernet radiusCodeAccessChallengeTLSPacket = | ||
468 | - constructRADIUSCodeAccessChallengePacket(RADIUS.RADIUS_CODE_ACCESS_CHALLENGE, EAP.ATTR_TLS); | ||
469 | - sendPacket(radiusCodeAccessChallengeTLSPacket); | ||
470 | 234 | ||
471 | - Ethernet radiusChallengeTLSPacket = fetchPacket(4); | 235 | + RADIUS successPacket = |
472 | - checkRadiusPacket(radiusChallengeTLSPacket, EAP.ATTR_TLS); | ||
473 | - | ||
474 | - // (6) Supplicant TLS response | ||
475 | - | ||
476 | - Ethernet tlsRadiusPacket = constructSupplicantIdentifyPacket(EAP.ATTR_TLS); | ||
477 | - sendPacket(tlsRadiusPacket); | ||
478 | - Ethernet supplicantTLSResponsePacket = fetchPacket(5); | ||
479 | - RADIUS responseTLSRadiusPacket = checkAndFetchRADIUSPacketFromSupplicant(supplicantTLSResponsePacket); | ||
480 | - assertThat(responseTLSRadiusPacket.getIdentifier(), is((byte) 0)); | ||
481 | - assertThat(responseTLSRadiusPacket.getCode(), is(RADIUS.RADIUS_CODE_ACCESS_REQUEST)); | ||
482 | - | ||
483 | - // (7) RADIUS Success | ||
484 | - | ||
485 | - Ethernet successPacket = | ||
486 | constructRADIUSCodeAccessChallengePacket(RADIUS.RADIUS_CODE_ACCESS_ACCEPT, EAP.SUCCESS); | 236 | constructRADIUSCodeAccessChallengePacket(RADIUS.RADIUS_CODE_ACCESS_ACCEPT, EAP.SUCCESS); |
487 | - sendPacket(successPacket); | 237 | + aaa.radiusListener.handleRadiusPacket((successPacket)); |
488 | - Ethernet supplicantSuccessPacket = fetchPacket(6); | 238 | + Ethernet supplicantSuccessPacket = (Ethernet) fetchPacket(4); |
489 | 239 | ||
490 | - checkRadiusPacket(supplicantSuccessPacket, EAP.SUCCESS); | 240 | + checkRadiusPacket(aaa, supplicantSuccessPacket, EAP.SUCCESS); |
491 | 241 | ||
492 | // State machine should be in authorized state | 242 | // State machine should be in authorized state |
493 | 243 | ||
494 | assertThat(stateMachine, notNullValue()); | 244 | assertThat(stateMachine, notNullValue()); |
495 | assertThat(stateMachine.state(), is(StateMachine.STATE_AUTHORIZED)); | 245 | assertThat(stateMachine.state(), is(StateMachine.STATE_AUTHORIZED)); |
246 | + | ||
496 | } | 247 | } |
497 | 248 | ||
498 | /** | 249 | /** |
... | @@ -502,7 +253,7 @@ public class AAATest { | ... | @@ -502,7 +253,7 @@ public class AAATest { |
502 | public void testConfig() { | 253 | public void testConfig() { |
503 | assertThat(aaa.nasIpAddress.getHostAddress(), is(AAAConfig.DEFAULT_NAS_IP)); | 254 | assertThat(aaa.nasIpAddress.getHostAddress(), is(AAAConfig.DEFAULT_NAS_IP)); |
504 | assertThat(aaa.nasMacAddress, is(AAAConfig.DEFAULT_NAS_MAC)); | 255 | assertThat(aaa.nasMacAddress, is(AAAConfig.DEFAULT_NAS_MAC)); |
505 | - assertThat(aaa.radiusIpAddress.getHostAddress(), is(AAAConfig.DEFAULT_RADIUS_IP)); | 256 | + assertThat(aaa.radiusIpAddress.getHostAddress(), is(BAD_IP_ADDRESS)); |
506 | assertThat(aaa.radiusMacAddress, is(AAAConfig.DEFAULT_RADIUS_MAC)); | 257 | assertThat(aaa.radiusMacAddress, is(AAAConfig.DEFAULT_RADIUS_MAC)); |
507 | } | 258 | } |
508 | } | 259 | } | ... | ... |
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
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 | + */ | ||
16 | +package org.onosproject.aaa; | ||
17 | + | ||
18 | +import java.nio.ByteBuffer; | ||
19 | +import java.security.MessageDigest; | ||
20 | +import java.util.LinkedList; | ||
21 | +import java.util.List; | ||
22 | + | ||
23 | +import org.onlab.packet.BasePacket; | ||
24 | +import org.onlab.packet.EAP; | ||
25 | +import org.onlab.packet.EAPOL; | ||
26 | +import org.onlab.packet.EthType; | ||
27 | +import org.onlab.packet.Ethernet; | ||
28 | +import org.onlab.packet.MacAddress; | ||
29 | +import org.onosproject.net.packet.DefaultInboundPacket; | ||
30 | +import org.onosproject.net.packet.DefaultPacketContext; | ||
31 | +import org.onosproject.net.packet.InboundPacket; | ||
32 | +import org.onosproject.net.packet.OutboundPacket; | ||
33 | +import org.onosproject.net.packet.PacketContext; | ||
34 | +import org.onosproject.net.packet.PacketProcessor; | ||
35 | +import org.onosproject.net.packet.PacketServiceAdapter; | ||
36 | + | ||
37 | +import static org.hamcrest.Matchers.instanceOf; | ||
38 | +import static org.hamcrest.Matchers.is; | ||
39 | +import static org.hamcrest.Matchers.notNullValue; | ||
40 | +import static org.junit.Assert.assertThat; | ||
41 | +import static org.junit.Assert.fail; | ||
42 | +import static org.onosproject.net.NetTestTools.connectPoint; | ||
43 | + | ||
44 | +/** | ||
45 | + * Common methods for AAA app testing. | ||
46 | + */ | ||
47 | +public class AAATestBase { | ||
48 | + | ||
49 | + MacAddress clientMac = MacAddress.valueOf("1a:1a:1a:1a:1a:1a"); | ||
50 | + MacAddress serverMac = MacAddress.valueOf("2a:2a:2a:2a:2a:2a"); | ||
51 | + | ||
52 | + // Our session id will be the device ID ("of:1") with the port ("1") concatenated | ||
53 | + static final String SESSION_ID = "of:11"; | ||
54 | + | ||
55 | + List<BasePacket> savedPackets = new LinkedList<>(); | ||
56 | + PacketProcessor packetProcessor; | ||
57 | + | ||
58 | + /** | ||
59 | + * Saves the given packet onto the saved packets list. | ||
60 | + * | ||
61 | + * @param packet packet to save | ||
62 | + */ | ||
63 | + void savePacket(BasePacket packet) { | ||
64 | + savedPackets.add(packet); | ||
65 | + } | ||
66 | + | ||
67 | + /** | ||
68 | + * Keeps a reference to the PacketProcessor and saves the OutboundPackets. | ||
69 | + */ | ||
70 | + class MockPacketService extends PacketServiceAdapter { | ||
71 | + | ||
72 | + @Override | ||
73 | + public void addProcessor(PacketProcessor processor, int priority) { | ||
74 | + packetProcessor = processor; | ||
75 | + } | ||
76 | + | ||
77 | + @Override | ||
78 | + public void emit(OutboundPacket packet) { | ||
79 | + try { | ||
80 | + Ethernet eth = Ethernet.deserializer().deserialize(packet.data().array(), | ||
81 | + 0, packet.data().array().length); | ||
82 | + savePacket(eth); | ||
83 | + } catch (Exception e) { | ||
84 | + fail(e.getMessage()); | ||
85 | + } | ||
86 | + } | ||
87 | + } | ||
88 | + | ||
89 | + /** | ||
90 | + * Mocks the DefaultPacketContext. | ||
91 | + */ | ||
92 | + final class TestPacketContext extends DefaultPacketContext { | ||
93 | + | ||
94 | + private TestPacketContext(long time, InboundPacket inPkt, | ||
95 | + OutboundPacket outPkt, boolean block) { | ||
96 | + super(time, inPkt, outPkt, block); | ||
97 | + } | ||
98 | + | ||
99 | + @Override | ||
100 | + public void send() { | ||
101 | + // We don't send anything out. | ||
102 | + } | ||
103 | + } | ||
104 | + | ||
105 | + /** | ||
106 | + * Sends an Ethernet packet to the process method of the Packet Processor. | ||
107 | + * | ||
108 | + * @param reply Ethernet packet | ||
109 | + */ | ||
110 | + void sendPacket(Ethernet reply) { | ||
111 | + final ByteBuffer byteBuffer = ByteBuffer.wrap(reply.serialize()); | ||
112 | + InboundPacket inPacket = new DefaultInboundPacket(connectPoint("1", 1), | ||
113 | + reply, | ||
114 | + byteBuffer); | ||
115 | + | ||
116 | + PacketContext context = new TestPacketContext(127L, inPacket, null, false); | ||
117 | + packetProcessor.process(context); | ||
118 | + } | ||
119 | + | ||
120 | + /** | ||
121 | + * Constructs an Ethernet packet containing identification payload. | ||
122 | + * | ||
123 | + * @return Ethernet packet | ||
124 | + */ | ||
125 | + Ethernet constructSupplicantIdentifyPacket(StateMachine stateMachine, | ||
126 | + byte type, | ||
127 | + byte id, | ||
128 | + Ethernet radiusChallenge) | ||
129 | + throws Exception { | ||
130 | + Ethernet eth = new Ethernet(); | ||
131 | + eth.setDestinationMACAddress(clientMac.toBytes()); | ||
132 | + eth.setSourceMACAddress(serverMac.toBytes()); | ||
133 | + eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort()); | ||
134 | + eth.setVlanID((short) 2); | ||
135 | + | ||
136 | + String username = "testuser"; | ||
137 | + byte[] data = username.getBytes(); | ||
138 | + | ||
139 | + | ||
140 | + if (type == EAP.ATTR_MD5) { | ||
141 | + String password = "testpassword"; | ||
142 | + EAPOL eapol = (EAPOL) radiusChallenge.getPayload(); | ||
143 | + EAP eap = (EAP) eapol.getPayload(); | ||
144 | + | ||
145 | + byte[] identifier = new byte[password.length() + eap.getData().length]; | ||
146 | + | ||
147 | + identifier[0] = stateMachine.challengeIdentifier(); | ||
148 | + System.arraycopy(password.getBytes(), 0, identifier, 1, password.length()); | ||
149 | + System.arraycopy(eap.getData(), 1, identifier, 1 + password.length(), 16); | ||
150 | + | ||
151 | + MessageDigest md = MessageDigest.getInstance("MD5"); | ||
152 | + byte[] hash = md.digest(identifier); | ||
153 | + data = new byte[17]; | ||
154 | + data[0] = (byte) 16; | ||
155 | + System.arraycopy(hash, 0, data, 1, 16); | ||
156 | + } | ||
157 | + EAP eap = new EAP(EAP.RESPONSE, (byte) 1, type, | ||
158 | + data); | ||
159 | + eap.setIdentifier(id); | ||
160 | + | ||
161 | + // eapol header | ||
162 | + EAPOL eapol = new EAPOL(); | ||
163 | + eapol.setEapolType(EAPOL.EAPOL_PACKET); | ||
164 | + eapol.setPacketLength(eap.getLength()); | ||
165 | + | ||
166 | + // eap part | ||
167 | + eapol.setPayload(eap); | ||
168 | + | ||
169 | + eth.setPayload(eapol); | ||
170 | + eth.setPad(true); | ||
171 | + return eth; | ||
172 | + } | ||
173 | + | ||
174 | + /** | ||
175 | + * Constructs an Ethernet packet containing a EAPOL_START Payload. | ||
176 | + * | ||
177 | + * @return Ethernet packet | ||
178 | + */ | ||
179 | + Ethernet constructSupplicantStartPacket() { | ||
180 | + Ethernet eth = new Ethernet(); | ||
181 | + eth.setDestinationMACAddress(clientMac.toBytes()); | ||
182 | + eth.setSourceMACAddress(serverMac.toBytes()); | ||
183 | + eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort()); | ||
184 | + eth.setVlanID((short) 2); | ||
185 | + | ||
186 | + EAP eap = new EAP(EAPOL.EAPOL_START, (byte) 2, EAPOL.EAPOL_START, null); | ||
187 | + | ||
188 | + // eapol header | ||
189 | + EAPOL eapol = new EAPOL(); | ||
190 | + eapol.setEapolType(EAPOL.EAPOL_START); | ||
191 | + eapol.setPacketLength(eap.getLength()); | ||
192 | + | ||
193 | + // eap part | ||
194 | + eapol.setPayload(eap); | ||
195 | + | ||
196 | + eth.setPayload(eapol); | ||
197 | + eth.setPad(true); | ||
198 | + return eth; | ||
199 | + } | ||
200 | + | ||
201 | + /** | ||
202 | + * Checks the contents of a RADIUS packet being sent to the RADIUS server. | ||
203 | + * | ||
204 | + * @param radiusPacket packet to check | ||
205 | + * @param code expected code | ||
206 | + */ | ||
207 | + void checkRadiusPacket(AAA aaa, Ethernet radiusPacket, byte code) { | ||
208 | + | ||
209 | + assertThat(radiusPacket.getSourceMAC(), | ||
210 | + is(MacAddress.valueOf(aaa.nasMacAddress))); | ||
211 | + assertThat(radiusPacket.getDestinationMAC(), is(serverMac)); | ||
212 | + | ||
213 | + assertThat(radiusPacket.getPayload(), instanceOf(EAPOL.class)); | ||
214 | + EAPOL eapol = (EAPOL) radiusPacket.getPayload(); | ||
215 | + assertThat(eapol, notNullValue()); | ||
216 | + | ||
217 | + assertThat(eapol.getEapolType(), is(EAPOL.EAPOL_PACKET)); | ||
218 | + assertThat(eapol.getPayload(), instanceOf(EAP.class)); | ||
219 | + EAP eap = (EAP) eapol.getPayload(); | ||
220 | + assertThat(eap, notNullValue()); | ||
221 | + | ||
222 | + assertThat(eap.getCode(), is(code)); | ||
223 | + } | ||
224 | +} |
... | @@ -21,7 +21,9 @@ import org.junit.After; | ... | @@ -21,7 +21,9 @@ import org.junit.After; |
21 | import org.junit.Assert; | 21 | import org.junit.Assert; |
22 | import org.junit.Before; | 22 | import org.junit.Before; |
23 | import org.junit.Test; | 23 | import org.junit.Test; |
24 | -import static org.junit.Assert.*; | 24 | + |
25 | +import static org.junit.Assert.assertEquals; | ||
26 | +import static org.junit.Assert.assertNull; | ||
25 | 27 | ||
26 | 28 | ||
27 | public class StateMachineTest { | 29 | public class StateMachineTest { | ... | ... |
-
Please register or login to post a comment