Ray Milkey
Committed by Gerrit Code Review

Support RADIUS server outside of the ONOS network

Change-Id: I7e64faae6831467e084db878e02023d40fb33f07
...@@ -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 +
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 {
......