blob: 227f4e8bc63e27f07ffb4a0a2742370ae046491e [file] [log] [blame]
Ari Saha89831742015-06-26 10:31:48 -07001/*
2 *
3 * Copyright 2015 AT&T Foundry
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19package org.onosproject.aaa;
20
21import org.onlab.packet.MacAddress;
22import org.onosproject.net.ConnectPoint;
23import org.onosproject.xosintegration.VoltTenant;
24import org.onosproject.xosintegration.VoltTenantService;
25import org.slf4j.Logger;
Thomas Vachuskae9894202015-07-30 11:59:07 -070026
Ari Saha89831742015-06-26 10:31:48 -070027import java.util.BitSet;
28
29import static org.slf4j.LoggerFactory.getLogger;
30
31/**
32 * AAA Finite State Machine.
33 */
34
35class StateMachine {
36 //INDEX to identify the state in the transition table
37 static final int STATE_IDLE = 0;
38 static final int STATE_STARTED = 1;
39 static final int STATE_PENDING = 2;
40 static final int STATE_AUTHORIZED = 3;
41 static final int STATE_UNAUTHORIZED = 4;
42
43 //INDEX to identify the transition in the transition table
44 static final int TRANSITION_START = 0; // --> started
45 static final int TRANSITION_REQUEST_ACCESS = 1;
46 static final int TRANSITION_AUTHORIZE_ACCESS = 2;
47 static final int TRANSITION_DENY_ACCESS = 3;
48 static final int TRANSITION_LOGOFF = 4;
49
50 //map of access identifiers (issued at EAPOL START)
51 static BitSet bitSet = new BitSet();
52 private final VoltTenantService voltService;
53
54 private int identifier = -1;
55 private byte challengeIdentifier;
56 private byte[] challengeState;
57 private byte[] username;
58 private byte[] requestAuthenticator;
59
60 // Supplicant connectivity info
61 protected ConnectPoint supplicantConnectpoint;
62 protected MacAddress supplicantAddress;
63 protected short vlanId;
64
65 private String sessionId = null;
66
67 private final Logger log = getLogger(getClass());
68
69
70 private State[] states = {
71 new Idle(), new Started(), new Pending(), new Authorized(), new Unauthorized()
72 };
73
74
75 //State transition table
76 /*
77
78 state IDLE | STARTED | PENDING | AUTHORIZED | UNAUTHORIZED
79 ////
80 input
81 ----------------------------------------------------------------------------------------------------
82
83 START STARTED | _ | _ | _ | _
84
85 REQUEST_ACCESS _ | PENDING | _ | _ | _
86
87 AUTHORIZE_ACCESS _ | _ | AUTHORIZED | _ | _
88
89 DENY_ACCESS _ | - | UNAUTHORIZED | _ | _
90
91 LOGOFF _ | _ | _ | IDLE | IDLE
92 */
93
94 private int[] idleTransition =
95 {STATE_STARTED, STATE_IDLE, STATE_IDLE, STATE_IDLE, STATE_IDLE};
96 private int[] startedTransition =
97 {STATE_STARTED, STATE_PENDING, STATE_STARTED, STATE_STARTED, STATE_STARTED};
98 private int[] pendingTransition =
99 {STATE_PENDING, STATE_PENDING, STATE_AUTHORIZED, STATE_UNAUTHORIZED, STATE_PENDING};
100 private int[] authorizedTransition =
101 {STATE_AUTHORIZED, STATE_AUTHORIZED, STATE_AUTHORIZED, STATE_AUTHORIZED, STATE_IDLE};
102 private int[] unauthorizedTransition =
103 {STATE_UNAUTHORIZED, STATE_UNAUTHORIZED, STATE_UNAUTHORIZED, STATE_UNAUTHORIZED, STATE_IDLE};
104
105 //THE TRANSITION TABLE
106 private int[][] transition =
107 {idleTransition, startedTransition, pendingTransition, authorizedTransition,
108 unauthorizedTransition};
109
110 private int currentState = STATE_IDLE;
111
112
113 /**
114 * State Machine Constructor.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700115 *
116 * @param sessionId session Id represented by the switch dpid + port number
117 * @param voltService volt service reference
Ari Saha89831742015-06-26 10:31:48 -0700118 */
119 public StateMachine(String sessionId, VoltTenantService voltService) {
120 log.info("Creating a new state machine for {}", sessionId);
121 this.sessionId = sessionId;
122 this.voltService = voltService;
123
124 }
125
126 /**
127 * Get the client id that is requesting for access.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700128 *
Ari Saha89831742015-06-26 10:31:48 -0700129 * @return The client id.
130 */
131 public String getSessionId() {
132 return this.sessionId;
133 }
134
135 /**
136 * Create the identifier for the state machine (happens when goes to STARTED state).
137 */
138 private void createIdentifier() throws StateMachineException {
139 log.debug("Creating Identifier.");
Ray Milkey78e95a42015-09-24 08:36:45 -0700140 int index;
Ari Saha89831742015-06-26 10:31:48 -0700141
142 try {
143 //find the first available spot for identifier assignment
144 index = StateMachine.bitSet.nextClearBit(0);
145
146 //there is a limit of 256 identifiers
147 if (index == 256) {
148 throw new StateMachineException("Cannot handle any new identifier. Limit is 256.");
149 }
150 } catch (IndexOutOfBoundsException e) {
151 throw new StateMachineException(e.getMessage());
152 }
153
154 log.info("Assigning identifier {}", index);
155 StateMachine.bitSet.set(index);
156 this.identifier = index;
157 }
158
159 /**
160 * Set the challenge identifier and the state issued by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700161 *
Ari Saha89831742015-06-26 10:31:48 -0700162 * @param challengeIdentifier The challenge identifier set into the EAP packet from the RADIUS message.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700163 * @param challengeState The challenge state from the RADIUS.
Ari Saha89831742015-06-26 10:31:48 -0700164 */
165 protected void setChallengeInfo(byte challengeIdentifier, byte[] challengeState) {
166 this.challengeIdentifier = challengeIdentifier;
167 this.challengeState = challengeState;
168 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700169
Ari Saha89831742015-06-26 10:31:48 -0700170 /**
171 * Set the challenge identifier issued by the RADIUS on the access challenge request.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700172 *
Ari Saha89831742015-06-26 10:31:48 -0700173 * @param challengeIdentifier The challenge identifier set into the EAP packet from the RADIUS message.
174 */
175 protected void setChallengeIdentifier(byte challengeIdentifier) {
176 log.info("Set Challenge Identifier to {}", challengeIdentifier);
177 this.challengeIdentifier = challengeIdentifier;
178 }
179
180 /**
181 * Get the challenge EAP identifier set by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700182 *
Ari Saha89831742015-06-26 10:31:48 -0700183 * @return The challenge EAP identifier.
184 */
185 protected byte getChallengeIdentifier() {
186 return this.challengeIdentifier;
187 }
188
189
190 /**
191 * Set the challenge state info issued by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700192 *
Ari Saha89831742015-06-26 10:31:48 -0700193 * @param challengeState The challenge state from the RADIUS.
194 */
195 protected void setChallengeState(byte[] challengeState) {
196 log.info("Set Challenge State");
197 this.challengeState = challengeState;
198 }
199
200 /**
201 * Get the challenge state set by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700202 *
Ari Saha89831742015-06-26 10:31:48 -0700203 * @return The challenge state.
204 */
205 protected byte[] getChallengeState() {
206 return this.challengeState;
207 }
208
209 /**
210 * Set the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700211 *
Ari Saha89831742015-06-26 10:31:48 -0700212 * @param username The username sent to the RADIUS upon access request.
213 */
214 protected void setUsername(byte[] username) {
215 this.username = username;
216 }
217
218
219 /**
220 * Get the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700221 *
Ari Saha89831742015-06-26 10:31:48 -0700222 * @return The requestAuthenticator.
223 */
224 protected byte[] getReqeustAuthenticator() {
225 return this.requestAuthenticator;
226 }
227
228 /**
229 * Set the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700230 *
Ari Saha89831742015-06-26 10:31:48 -0700231 * @param authenticator The username sent to the RADIUS upon access request.
232 */
233 protected void setRequestAuthenticator(byte[] authenticator) {
234 this.requestAuthenticator = authenticator;
235 }
236
237
238 /**
239 * Get the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700240 *
Ari Saha89831742015-06-26 10:31:48 -0700241 * @return The username.
242 */
243 protected byte[] getUsername() {
244 return this.username;
245 }
246
247 /**
248 * Return the identifier of the state machine.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700249 *
Ari Saha89831742015-06-26 10:31:48 -0700250 * @return The state machine identifier.
251 */
252 public byte getIdentifier() {
253 return (byte) this.identifier;
254 }
255
256
257 protected void deleteIdentifier() {
258 if (this.identifier != -1) {
259 log.info("Freeing up " + this.identifier);
260 //this state machine should be deleted and free up the identifier
261 StateMachine.bitSet.clear(this.identifier);
262 this.identifier = -1;
263 }
264 }
265
266
267 /**
268 * Move to the next state.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700269 *
Ray Milkey78e95a42015-09-24 08:36:45 -0700270 * @param msg message
Ari Saha89831742015-06-26 10:31:48 -0700271 */
Thomas Vachuskae9894202015-07-30 11:59:07 -0700272 private void next(int msg) {
Ari Saha89831742015-06-26 10:31:48 -0700273 currentState = transition[currentState][msg];
274 log.info("Current State " + currentState);
275 }
276
277 /**
278 * Client has requested the start action to allow network access.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700279 *
280 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700281 */
282 public void start() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700283 states[currentState].start();
284 //move to the next state
285 next(TRANSITION_START);
286 createIdentifier();
Ari Saha89831742015-06-26 10:31:48 -0700287 }
288
289 /**
290 * An Identification information has been sent by the supplicant.
291 * Move to the next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700292 *
293 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700294 */
295 public void requestAccess() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700296 states[currentState].requestAccess();
297 //move to the next state
298 next(TRANSITION_REQUEST_ACCESS);
Ari Saha89831742015-06-26 10:31:48 -0700299 }
300
301 /**
302 * RADIUS has accepted the identification.
303 * Move to the next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700304 *
305 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700306 */
307 public void authorizeAccess() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700308 states[currentState].radiusAccepted();
309 //move to the next state
310 next(TRANSITION_AUTHORIZE_ACCESS);
Ari Saha89831742015-06-26 10:31:48 -0700311
Ray Milkey78e95a42015-09-24 08:36:45 -0700312 if (voltService != null) {
313 voltService.addTenant(
314 VoltTenant.builder()
315 .withHumanReadableName("VCPE-" + this.identifier)
316 .withId(this.identifier)
317 .withProviderService(1)
318 .withServiceSpecificId(String.valueOf(this.identifier))
319 .withPort(this.supplicantConnectpoint)
320 .withVlanId(String.valueOf(this.vlanId)).build());
Ari Saha89831742015-06-26 10:31:48 -0700321 }
322
Ray Milkey78e95a42015-09-24 08:36:45 -0700323 deleteIdentifier();
Ari Saha89831742015-06-26 10:31:48 -0700324 }
325
326 /**
327 * RADIUS has denied the identification.
328 * Move to the next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700329 *
330 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700331 */
332 public void denyAccess() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700333 states[currentState].radiusDenied();
334 //move to the next state
335 next(TRANSITION_DENY_ACCESS);
336 deleteIdentifier();
Ari Saha89831742015-06-26 10:31:48 -0700337 }
338
339 /**
340 * Logoff request has been requested.
341 * Move to the next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700342 *
343 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700344 */
345 public void logoff() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700346 states[currentState].logoff();
347 //move to the next state
348 next(TRANSITION_LOGOFF);
Ari Saha89831742015-06-26 10:31:48 -0700349 }
350
351 /**
352 * Get the current state.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700353 *
Ari Saha89831742015-06-26 10:31:48 -0700354 * @return The current state. Could be STATE_IDLE, STATE_STARTED, STATE_PENDING, STATE_AUTHORIZED,
355 * STATE_UNAUTHORIZED.
356 */
357 public int getState() {
358 return currentState;
359 }
360
361
Ari Saha89831742015-06-26 10:31:48 -0700362 public String toString() {
363 return ("sessionId: " + this.sessionId) + "\t" + ("identifier: " + this.identifier) + "\t" +
364 ("state: " + this.currentState);
365 }
Ari Saha89831742015-06-26 10:31:48 -0700366
Ray Milkey78e95a42015-09-24 08:36:45 -0700367 abstract class State {
368 private final Logger log = getLogger(getClass());
Thomas Vachuskae9894202015-07-30 11:59:07 -0700369
Ray Milkey78e95a42015-09-24 08:36:45 -0700370 private String name = "State";
Ari Saha89831742015-06-26 10:31:48 -0700371
Ray Milkey78e95a42015-09-24 08:36:45 -0700372 public void start() throws StateMachineInvalidTransitionException {
373 log.warn("START transition from this state is not allowed.");
374 }
Ari Saha89831742015-06-26 10:31:48 -0700375
Ray Milkey78e95a42015-09-24 08:36:45 -0700376 public void requestAccess() throws StateMachineInvalidTransitionException {
377 log.warn("REQUEST ACCESS transition from this state is not allowed.");
378 }
379
380 public void radiusAccepted() throws StateMachineInvalidTransitionException {
381 log.warn("AUTHORIZE ACCESS transition from this state is not allowed.");
382 }
383
384 public void radiusDenied() throws StateMachineInvalidTransitionException {
385 log.warn("DENY ACCESS transition from this state is not allowed.");
386 }
387
388 public void logoff() throws StateMachineInvalidTransitionException {
389 log.warn("LOGOFF transition from this state is not allowed.");
390 }
Ari Saha89831742015-06-26 10:31:48 -0700391 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700392
Ray Milkey78e95a42015-09-24 08:36:45 -0700393 /**
394 * Idle state: supplicant is logged of from the network.
395 */
396 class Idle extends State {
397 private final Logger log = getLogger(getClass());
398 private String name = "IDLE_STATE";
399
400 public void start() {
401 log.info("Moving from IDLE state to STARTED state.");
402 }
Ari Saha89831742015-06-26 10:31:48 -0700403 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700404
Ray Milkey78e95a42015-09-24 08:36:45 -0700405 /**
406 * Started state: supplicant has entered the network and informed the authenticator.
407 */
408 class Started extends State {
409 private final Logger log = getLogger(getClass());
410 private String name = "STARTED_STATE";
411
412 public void requestAccess() {
413 log.info("Moving from STARTED state to PENDING state.");
414 }
Ari Saha89831742015-06-26 10:31:48 -0700415 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700416
Ray Milkey78e95a42015-09-24 08:36:45 -0700417 /**
418 * Pending state: supplicant has been identified by the authenticator but has not access yet.
419 */
420 class Pending extends State {
421 private final Logger log = getLogger(getClass());
422 private String name = "PENDING_STATE";
423
424 public void radiusAccepted() {
425 log.info("Moving from PENDING state to AUTHORIZED state.");
426 }
427
428 public void radiusDenied() {
429 log.info("Moving from PENDING state to UNAUTHORIZED state.");
430 }
Ari Saha89831742015-06-26 10:31:48 -0700431 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700432
Ray Milkey78e95a42015-09-24 08:36:45 -0700433 /**
434 * Authorized state: supplicant port has been accepted, access is granted.
435 */
436 class Authorized extends State {
437 private final Logger log = getLogger(getClass());
438 private String name = "AUTHORIZED_STATE";
Ari Saha89831742015-06-26 10:31:48 -0700439
Ray Milkey78e95a42015-09-24 08:36:45 -0700440 public void logoff() {
Ari Saha89831742015-06-26 10:31:48 -0700441
Ray Milkey78e95a42015-09-24 08:36:45 -0700442 log.info("Moving from AUTHORIZED state to IDLE state.");
443 }
Ari Saha89831742015-06-26 10:31:48 -0700444 }
445
Ray Milkey78e95a42015-09-24 08:36:45 -0700446 /**
447 * Unauthorized state: supplicant port has been rejected, access is denied.
448 */
449 class Unauthorized extends State {
450 private final Logger log = getLogger(getClass());
451 private String name = "UNAUTHORIZED_STATE";
452
453 public void logoff() {
454 log.info("Moving from UNAUTHORIZED state to IDLE state.");
455 }
Ari Saha89831742015-06-26 10:31:48 -0700456 }
Ari Saha89831742015-06-26 10:31:48 -0700457
458
Ari Saha89831742015-06-26 10:31:48 -0700459}