blob: 744b0ae514e16a1b694d4dff374cab2ef0ad25a6 [file] [log] [blame]
Ari Saha89831742015-06-26 10:31:48 -07001/*
Amit Ghoshc9ac1e52017-07-28 12:31:18 +01002 * Copyright 2017-present Open Networking Foundation
Ari Saha89831742015-06-26 10:31:48 -07003 *
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 */
17
Matteo Scandolocf847b82019-04-26 15:00:00 -070018package org.opencord.aaa.impl;
Ari Saha89831742015-06-26 10:31:48 -070019
20import org.onlab.packet.MacAddress;
21import org.onosproject.net.ConnectPoint;
Matteo Scandolocf847b82019-04-26 15:00:00 -070022import org.opencord.aaa.AuthenticationEvent;
23import org.opencord.aaa.StateMachineDelegate;
Ari Saha89831742015-06-26 10:31:48 -070024import org.slf4j.Logger;
Thomas Vachuskae9894202015-07-30 11:59:07 -070025
Shubham Sharma4900ce62019-06-19 14:18:50 +000026import java.util.HashSet;
Shubham Sharma4900ce62019-06-19 14:18:50 +000027import java.util.Set;
Jonathan Hart612651f2019-11-25 09:21:43 -080028import java.util.concurrent.ScheduledExecutorService;
29import java.util.concurrent.TimeUnit;
Shubham Sharma4900ce62019-06-19 14:18:50 +000030
31import static org.slf4j.LoggerFactory.getLogger;
Ari Saha89831742015-06-26 10:31:48 -070032
33/**
34 * AAA Finite State Machine.
35 */
Carmelo Cascone58b53292019-09-30 12:35:31 -070036public class StateMachine {
Ari Saha89831742015-06-26 10:31:48 -070037 //INDEX to identify the state in the transition table
38 static final int STATE_IDLE = 0;
39 static final int STATE_STARTED = 1;
40 static final int STATE_PENDING = 2;
41 static final int STATE_AUTHORIZED = 3;
42 static final int STATE_UNAUTHORIZED = 4;
43
Shubham Sharma1e43c562019-06-19 14:18:12 +000044 // Defining the states where timeout can happen
Jonathan Hart612651f2019-11-25 09:21:43 -080045 static final Set<Integer> TIMEOUT_ELIGIBLE_STATES = new HashSet<>();
Shubham Sharma1e43c562019-06-19 14:18:12 +000046 static {
47 TIMEOUT_ELIGIBLE_STATES.add(STATE_STARTED);
48 TIMEOUT_ELIGIBLE_STATES.add(STATE_PENDING);
49 }
50 // INDEX to identify the transition in the transition table
Ari Saha89831742015-06-26 10:31:48 -070051 static final int TRANSITION_START = 0; // --> started
52 static final int TRANSITION_REQUEST_ACCESS = 1;
53 static final int TRANSITION_AUTHORIZE_ACCESS = 2;
54 static final int TRANSITION_DENY_ACCESS = 3;
55 static final int TRANSITION_LOGOFF = 4;
56
Jonathan Hart612651f2019-11-25 09:21:43 -080057 private static int identifier = -1;
Ari Saha89831742015-06-26 10:31:48 -070058 private byte challengeIdentifier;
59 private byte[] challengeState;
60 private byte[] username;
61 private byte[] requestAuthenticator;
62
63 // Supplicant connectivity info
Ray Milkeyf61a24e2015-09-24 16:34:02 -070064 private ConnectPoint supplicantConnectpoint;
65 private MacAddress supplicantAddress;
66 private short vlanId;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010067 private byte priorityCode;
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +000068 private long sessionStartTime;
69 private String eapolTypeVal;
70
71 public enum EapolType {
72 EAPOL_PACKET("EAPOL_PACKET"),
73 EAPOL_START("EAPOL_START"),
74 EAPOL_LOGOFF("EAPOL_LOGOFF"),
75 EAPOL_KEY("EAPOL_KEY"),
76 EAPOL_ASF("EAPOL_ASF");
77
78 private final String eaptype;
79
80 private EapolType(String value) {
81 this.eaptype = value;
82 }
83 };
84
85 private String sessionTerminateReason;
86
87 public enum SessionTerminationReasons {
88 SUPPLICANT_LOGOFF("SUPPLICANT_LOGOFF"),
89 TIME_OUT("TIME_OUT"),
90 PORT_REMOVED("PORT_REMOVED");
91
92 private final String reason;
93
94 private SessionTerminationReasons(String value) {
95 this.reason = value;
96 }
97
98 public String getReason() {
99 return this.reason;
100 }
101 };
102
103 // Supplicant packet count
104 private int totalPacketsSent;
105 private int totalPacketsReceived;
106 private int totalOctetSent;
107 private int totalOctetReceived;
Ari Saha89831742015-06-26 10:31:48 -0700108
Shubham Sharma1e43c562019-06-19 14:18:12 +0000109 // Boolean flag indicating whether response is pending from AAA Server.
110 // Used for counting timeout happening for AAA Sessions due to no response.
111 private boolean waitingForRadiusResponse;
112
113 private static int cleanupTimerTimeOutInMins;
114
Ari Saha89831742015-06-26 10:31:48 -0700115 private String sessionId = null;
116
117 private final Logger log = getLogger(getClass());
118
Shubham Sharma1e43c562019-06-19 14:18:12 +0000119 private State[] states = {new Idle(), new Started(), new Pending(), new Authorized(), new Unauthorized() };
Ari Saha89831742015-06-26 10:31:48 -0700120
Shubham Sharma1e43c562019-06-19 14:18:12 +0000121 // Cleanup Timer instance created for this session
Jonathan Hart612651f2019-11-25 09:21:43 -0800122 private ScheduledExecutorService executor;
Shubham Sharma1e43c562019-06-19 14:18:12 +0000123 private java.util.concurrent.ScheduledFuture<?> cleanupTimer = null;
Ari Saha89831742015-06-26 10:31:48 -0700124
Shubham Sharma1e43c562019-06-19 14:18:12 +0000125 // TimeStamp of last EAPOL or RADIUS message received.
126 private long lastPacketReceivedTime = 0;
127
128 // State transition table
Ari Saha89831742015-06-26 10:31:48 -0700129 /*
Shubham Sharma1e43c562019-06-19 14:18:12 +0000130 *
131 * state IDLE | STARTED | PENDING | AUTHORIZED | UNAUTHORIZED //// input
132 * -----------------------------------------------------------------------------
133 * -----------------------
134 *
135 * START STARTED | _ | _ | STARTED | STARTED
136 *
137 * REQUEST_ACCESS _ | PENDING | _ | _ | _
138 *
139 * AUTHORIZE_ACCESS _ | _ | AUTHORIZED | _ | _
140 *
141 * DENY_ACCESS _ | - | UNAUTHORIZED | _ | _
142 *
143 * LOGOFF _ | _ | _ | IDLE | IDLE
Ari Saha89831742015-06-26 10:31:48 -0700144 */
145
Shubham Sharma1e43c562019-06-19 14:18:12 +0000146 private int[] idleTransition = {STATE_STARTED, STATE_IDLE, STATE_IDLE, STATE_IDLE, STATE_IDLE };
147 private int[] startedTransition = {STATE_STARTED, STATE_PENDING, STATE_STARTED, STATE_STARTED, STATE_STARTED };
148 private int[] pendingTransition = {STATE_PENDING, STATE_PENDING, STATE_AUTHORIZED, STATE_UNAUTHORIZED,
149 STATE_PENDING };
150 private int[] authorizedTransition = {STATE_STARTED, STATE_AUTHORIZED, STATE_AUTHORIZED, STATE_AUTHORIZED,
151 STATE_IDLE };
152 private int[] unauthorizedTransition = {STATE_STARTED, STATE_UNAUTHORIZED, STATE_UNAUTHORIZED, STATE_UNAUTHORIZED,
153 STATE_IDLE };
Ari Saha89831742015-06-26 10:31:48 -0700154
Shubham Sharma1e43c562019-06-19 14:18:12 +0000155 // THE TRANSITION TABLE
156 private int[][] transition = {idleTransition, startedTransition, pendingTransition, authorizedTransition,
157 unauthorizedTransition };
Ari Saha89831742015-06-26 10:31:48 -0700158
159 private int currentState = STATE_IDLE;
160
Jonathan Hart5db44532018-07-12 18:13:54 -0700161 private static StateMachineDelegate delegate;
162
Matteo Scandolocf847b82019-04-26 15:00:00 -0700163 public static void setDelegate(StateMachineDelegate delegate) {
164 StateMachine.delegate = delegate;
Jonathan Hart5db44532018-07-12 18:13:54 -0700165 }
166
Shubham Sharma1e43c562019-06-19 14:18:12 +0000167 public static void setcleanupTimerTimeOutInMins(int cleanupTimerTimeoutInMins) {
168 cleanupTimerTimeOutInMins = cleanupTimerTimeoutInMins;
169 }
170
Jonathan Hart612651f2019-11-25 09:21:43 -0800171 private void scheduleTimeout() {
172 cleanupTimer = executor.schedule(this::timeout, cleanupTimerTimeOutInMins, TimeUnit.MINUTES);
173 }
174
Jonathan Hart5db44532018-07-12 18:13:54 -0700175 public static void unsetDelegate(StateMachineDelegate delegate) {
176 if (StateMachine.delegate == delegate) {
177 StateMachine.delegate = null;
178 }
179 }
180
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100181 public static void deleteStateMachineMapping(StateMachine machine) {
Shubham Sharma1e43c562019-06-19 14:18:12 +0000182 if (machine.cleanupTimer != null) {
183 machine.cleanupTimer.cancel(false);
184 machine.cleanupTimer = null;
185 }
186 }
187
Jonathan Hart612651f2019-11-25 09:21:43 -0800188 public void stop() {
189 if (cleanupTimer != null) {
190 cleanupTimer.cancel(false);
191 }
Shubham Sharma1e43c562019-06-19 14:18:12 +0000192 }
193
194 public boolean isWaitingForRadiusResponse() {
195 return waitingForRadiusResponse;
196 }
197
198 public void setWaitingForRadiusResponse(boolean waitingForRadiusResponse) {
199 this.waitingForRadiusResponse = waitingForRadiusResponse;
200 }
201
David K. Bainbridge62019492017-07-28 17:02:10 -0700202 /**
Jonathan Hart932bedc2018-07-12 13:46:09 -0700203 * Creates a new StateMachine with the given session ID.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700204 *
Shubham Sharma1e43c562019-06-19 14:18:12 +0000205 * @param sessionId session Id represented by the switch dpid + port number
Jonathan Hart612651f2019-11-25 09:21:43 -0800206 * @param executor executor to run background tasks on
Ari Saha89831742015-06-26 10:31:48 -0700207 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800208 public StateMachine(String sessionId, ScheduledExecutorService executor) {
Jonathan Hart932bedc2018-07-12 13:46:09 -0700209 log.info("Creating a new state machine for {}", sessionId);
Ari Saha89831742015-06-26 10:31:48 -0700210 this.sessionId = sessionId;
Jonathan Hart612651f2019-11-25 09:21:43 -0800211 this.executor = executor;
Ari Saha89831742015-06-26 10:31:48 -0700212 }
213
214 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700215 * Gets the connect point for the supplicant side.
216 *
217 * @return supplicant connect point
218 */
219 public ConnectPoint supplicantConnectpoint() {
220 return supplicantConnectpoint;
221 }
222
223 /**
224 * Sets the supplicant side connect point.
225 *
226 * @param supplicantConnectpoint supplicant select point.
227 */
228 public void setSupplicantConnectpoint(ConnectPoint supplicantConnectpoint) {
229 this.supplicantConnectpoint = supplicantConnectpoint;
230 }
231
232 /**
233 * Gets the MAC address of the supplicant.
234 *
235 * @return supplicant MAC address
236 */
237 public MacAddress supplicantAddress() {
238 return supplicantAddress;
239 }
240
241 /**
242 * Sets the supplicant MAC address.
243 *
244 * @param supplicantAddress new supplicant MAC address
245 */
246 public void setSupplicantAddress(MacAddress supplicantAddress) {
247 this.supplicantAddress = supplicantAddress;
248 }
249
250 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000251 * Sets the lastPacketReceivedTime.
252 *
253 * @param lastPacketReceivedTime timelastPacket was received
254 */
255 public void setLastPacketReceivedTime(long lastPacketReceivedTime) {
256 this.lastPacketReceivedTime = lastPacketReceivedTime;
257 }
258
259 /**
260 * Gets the lastPacketReceivedTime.
261 *
262 * @return lastPacketReceivedTime
263 */
264 public long getLastPacketReceivedTime() {
265 return lastPacketReceivedTime;
266 }
267
268 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700269 * Gets the client's Vlan ID.
270 *
271 * @return client vlan ID
272 */
273 public short vlanId() {
274 return vlanId;
275 }
276
277 /**
278 * Sets the client's vlan ID.
279 *
280 * @param vlanId new client vlan ID
281 */
282 public void setVlanId(short vlanId) {
283 this.vlanId = vlanId;
284 }
285
286 /**
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100287 * Gets the client's priority Code.
288 *
289 * @return client Priority code
290 */
291 public byte priorityCode() {
292 return priorityCode;
293 }
294
295 /**
296 * Sets the client's priority Code.
297 *
298 * @param priorityCode new client priority Code
299 */
300 public void setPriorityCode(byte priorityCode) {
301 this.priorityCode = priorityCode;
302 }
303
304 /**
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +0000305 * Gets the session start time.
306 *
307 * @return session start time
308 */
309 public long sessionStartTime() {
310 return sessionStartTime;
311 }
312
313 /**
314 * Sets the session start time.
315 *
316 * @param sessionStartTime new session start time
317 */
318 public void setSessionStartTime(long sessionStartTime) {
319 this.sessionStartTime = sessionStartTime;
320 }
321
322 /**
323 * returns eapol Type.
324 *
325 * @return eapolTypeVal.
326 */
327 public String eapolType() {
328 return this.eapolTypeVal;
329 }
330
331 /**
332 * Sets eapol Type name from eapol value.
333 *
334 * @param value eapol type as byte.
335 */
336 public void setEapolTypeVal(byte value) {
337 switch (value) {
338 case (byte) 0: this.eapolTypeVal = EapolType.EAPOL_PACKET.eaptype;
339 break;
340 case (byte) 1: this.eapolTypeVal = EapolType.EAPOL_START.eaptype;
341 break;
342 case (byte) 2: this.eapolTypeVal = EapolType.EAPOL_LOGOFF.eaptype;
343 break;
344 case (byte) 3: this.eapolTypeVal = EapolType.EAPOL_KEY.eaptype;
345 break;
346 case (byte) 4: this.eapolTypeVal = EapolType.EAPOL_ASF.eaptype;
347 break;
348 default : this.eapolTypeVal = "INVALID TYPE";
349 }
350 }
351
352 public String getSessionTerminateReason() {
353 return sessionTerminateReason;
354 }
355
356 public void setSessionTerminateReason(String sessionTerminateReason) {
357 this.sessionTerminateReason = sessionTerminateReason;
358 }
359
360 public int totalPacketsReceived() {
361 return this.totalPacketsReceived;
362 }
363
364 public void incrementTotalPacketsReceived() {
365 this.totalPacketsReceived = this.totalPacketsReceived + 1;
366 }
367
368 public int totalPacketsSent() {
369 return this.totalPacketsSent;
370 }
371
372 public void incrementTotalPacketsSent() {
373 this.totalPacketsSent = this.totalPacketsSent + 1;
374 }
375
376 public void incrementTotalOctetReceived(short packetLen) {
377 this.totalOctetReceived = this.totalOctetReceived + packetLen;
378 }
379
380 public void incrementTotalOctetSent(short packetLen) {
381 this.totalOctetSent = this.totalOctetSent + packetLen;
382 }
383
384 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700385 * Gets the client id that is requesting for access.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700386 *
Ari Saha89831742015-06-26 10:31:48 -0700387 * @return The client id.
388 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700389 public String sessionId() {
Ari Saha89831742015-06-26 10:31:48 -0700390 return this.sessionId;
391 }
392
393 /**
Ari Saha89831742015-06-26 10:31:48 -0700394 * Set the challenge identifier and the state issued by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700395 *
Shubham Sharma1e43c562019-06-19 14:18:12 +0000396 * @param challengeIdentifier The challenge identifier set into the EAP packet
397 * from the RADIUS message.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700398 * @param challengeState The challenge state from the RADIUS.
Ari Saha89831742015-06-26 10:31:48 -0700399 */
400 protected void setChallengeInfo(byte challengeIdentifier, byte[] challengeState) {
401 this.challengeIdentifier = challengeIdentifier;
402 this.challengeState = challengeState;
403 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700404
Ari Saha89831742015-06-26 10:31:48 -0700405 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000406 * Set the challenge identifier issued by the RADIUS on the access challenge
407 * request.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700408 *
Shubham Sharma1e43c562019-06-19 14:18:12 +0000409 * @param challengeIdentifier The challenge identifier set into the EAP packet
410 * from the RADIUS message.
Ari Saha89831742015-06-26 10:31:48 -0700411 */
412 protected void setChallengeIdentifier(byte challengeIdentifier) {
413 log.info("Set Challenge Identifier to {}", challengeIdentifier);
414 this.challengeIdentifier = challengeIdentifier;
415 }
416
417 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700418 * Gets the challenge EAP identifier set by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700419 *
Ari Saha89831742015-06-26 10:31:48 -0700420 * @return The challenge EAP identifier.
421 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700422 protected byte challengeIdentifier() {
Ari Saha89831742015-06-26 10:31:48 -0700423 return this.challengeIdentifier;
424 }
425
Ari Saha89831742015-06-26 10:31:48 -0700426 /**
427 * Set the challenge state info issued by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700428 *
Ari Saha89831742015-06-26 10:31:48 -0700429 * @param challengeState The challenge state from the RADIUS.
430 */
431 protected void setChallengeState(byte[] challengeState) {
432 log.info("Set Challenge State");
433 this.challengeState = challengeState;
434 }
435
436 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700437 * Gets the challenge state set by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700438 *
Ari Saha89831742015-06-26 10:31:48 -0700439 * @return The challenge state.
440 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700441 protected byte[] challengeState() {
Ari Saha89831742015-06-26 10:31:48 -0700442 return this.challengeState;
443 }
444
445 /**
446 * Set the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700447 *
Ari Saha89831742015-06-26 10:31:48 -0700448 * @param username The username sent to the RADIUS upon access request.
449 */
450 protected void setUsername(byte[] username) {
451 this.username = username;
452 }
453
Ari Saha89831742015-06-26 10:31:48 -0700454 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700455 * Gets the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700456 *
Ari Saha89831742015-06-26 10:31:48 -0700457 * @return The requestAuthenticator.
458 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700459 protected byte[] requestAuthenticator() {
Ari Saha89831742015-06-26 10:31:48 -0700460 return this.requestAuthenticator;
461 }
462
463 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700464 * Sets the authenticator.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700465 *
Ari Saha89831742015-06-26 10:31:48 -0700466 * @param authenticator The username sent to the RADIUS upon access request.
467 */
468 protected void setRequestAuthenticator(byte[] authenticator) {
469 this.requestAuthenticator = authenticator;
470 }
471
Ari Saha89831742015-06-26 10:31:48 -0700472 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700473 * Gets the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700474 *
Ari Saha89831742015-06-26 10:31:48 -0700475 * @return The username.
476 */
Carmelo Cascone58b53292019-09-30 12:35:31 -0700477 public byte[] username() {
Ari Saha89831742015-06-26 10:31:48 -0700478 return this.username;
479 }
480
481 /**
482 * Return the identifier of the state machine.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700483 *
Ari Saha89831742015-06-26 10:31:48 -0700484 * @return The state machine identifier.
485 */
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100486 public synchronized byte identifier() {
Jonathan Hart612651f2019-11-25 09:21:43 -0800487 identifier = (identifier + 1) % 255;
488 return (byte) identifier;
Ari Saha89831742015-06-26 10:31:48 -0700489 }
490
Ari Saha89831742015-06-26 10:31:48 -0700491 /**
492 * Move to the next state.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700493 *
Ray Milkey78e95a42015-09-24 08:36:45 -0700494 * @param msg message
Ari Saha89831742015-06-26 10:31:48 -0700495 */
Thomas Vachuskae9894202015-07-30 11:59:07 -0700496 private void next(int msg) {
Ari Saha89831742015-06-26 10:31:48 -0700497 currentState = transition[currentState][msg];
498 log.info("Current State " + currentState);
499 }
500
501 /**
502 * Client has requested the start action to allow network access.
503 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800504 public void start() {
505 this.scheduleTimeout();
506
Ray Milkey78e95a42015-09-24 08:36:45 -0700507 states[currentState].start();
Jonathan Hart5db44532018-07-12 18:13:54 -0700508
Shubham Sharma1e43c562019-06-19 14:18:12 +0000509 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.STARTED, supplicantConnectpoint));
Jonathan Hart5db44532018-07-12 18:13:54 -0700510
Shubham Sharma1e43c562019-06-19 14:18:12 +0000511 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700512 next(TRANSITION_START);
Ari Saha89831742015-06-26 10:31:48 -0700513 }
514
515 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000516 * An Identification information has been sent by the supplicant. Move to the
517 * next state if possible.
Ari Saha89831742015-06-26 10:31:48 -0700518 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800519 public void requestAccess() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700520 states[currentState].requestAccess();
Jonathan Hart5db44532018-07-12 18:13:54 -0700521
Shubham Sharma1e43c562019-06-19 14:18:12 +0000522 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.REQUESTED, supplicantConnectpoint));
Jonathan Hart5db44532018-07-12 18:13:54 -0700523
Shubham Sharma1e43c562019-06-19 14:18:12 +0000524 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700525 next(TRANSITION_REQUEST_ACCESS);
Ari Saha89831742015-06-26 10:31:48 -0700526 }
527
528 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000529 * RADIUS has accepted the identification. Move to the next state if possible.
Ari Saha89831742015-06-26 10:31:48 -0700530 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800531 public void authorizeAccess() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700532 states[currentState].radiusAccepted();
Shubham Sharma1e43c562019-06-19 14:18:12 +0000533 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700534 next(TRANSITION_AUTHORIZE_ACCESS);
Ari Saha89831742015-06-26 10:31:48 -0700535
Shubham Sharma1e43c562019-06-19 14:18:12 +0000536 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.APPROVED, supplicantConnectpoint));
Ari Saha89831742015-06-26 10:31:48 -0700537
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100538 // Clear mapping
539 deleteStateMachineMapping(this);
Ari Saha89831742015-06-26 10:31:48 -0700540 }
541
542 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000543 * RADIUS has denied the identification. Move to the next state if possible.
Ari Saha89831742015-06-26 10:31:48 -0700544 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800545 public void denyAccess() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700546 states[currentState].radiusDenied();
Shubham Sharma1e43c562019-06-19 14:18:12 +0000547 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700548 next(TRANSITION_DENY_ACCESS);
Jonathan Hart5db44532018-07-12 18:13:54 -0700549
Shubham Sharma1e43c562019-06-19 14:18:12 +0000550 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.DENIED, supplicantConnectpoint));
Jonathan Hart5db44532018-07-12 18:13:54 -0700551
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100552 // Clear mappings
553 deleteStateMachineMapping(this);
Ari Saha89831742015-06-26 10:31:48 -0700554 }
555
556 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000557 * Logoff request has been requested. Move to the next state if possible.
Ari Saha89831742015-06-26 10:31:48 -0700558 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800559 public void logoff() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700560 states[currentState].logoff();
Shubham Sharma1e43c562019-06-19 14:18:12 +0000561 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700562 next(TRANSITION_LOGOFF);
Ari Saha89831742015-06-26 10:31:48 -0700563 }
564
565 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700566 * Gets the current state.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700567 *
Shubham Sharma1e43c562019-06-19 14:18:12 +0000568 * @return The current state. Could be STATE_IDLE, STATE_STARTED, STATE_PENDING,
569 * STATE_AUTHORIZED, STATE_UNAUTHORIZED.
Ari Saha89831742015-06-26 10:31:48 -0700570 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700571 public int state() {
Ari Saha89831742015-06-26 10:31:48 -0700572 return currentState;
573 }
574
Jonathan Hart612651f2019-11-25 09:21:43 -0800575 public String stateString() {
576 return states[currentState].name();
Ari Saha89831742015-06-26 10:31:48 -0700577 }
Ari Saha89831742015-06-26 10:31:48 -0700578
Jonathan Hart612651f2019-11-25 09:21:43 -0800579 @Override
580 public String toString() {
581 return ("sessionId: " + this.sessionId) + "\t" + ("state: " + this.currentState);
582 }
583
584 abstract static class State {
Ray Milkey78e95a42015-09-24 08:36:45 -0700585 private final Logger log = getLogger(getClass());
Thomas Vachuskae9894202015-07-30 11:59:07 -0700586
Jonathan Hart612651f2019-11-25 09:21:43 -0800587 abstract String name();
Ari Saha89831742015-06-26 10:31:48 -0700588
Jonathan Hart612651f2019-11-25 09:21:43 -0800589 public void start() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700590 log.warn("START transition from this state is not allowed.");
591 }
Ari Saha89831742015-06-26 10:31:48 -0700592
Jonathan Hart612651f2019-11-25 09:21:43 -0800593 public void requestAccess() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700594 log.warn("REQUEST ACCESS transition from this state is not allowed.");
595 }
596
Jonathan Hart612651f2019-11-25 09:21:43 -0800597 public void radiusAccepted() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700598 log.warn("AUTHORIZE ACCESS transition from this state is not allowed.");
599 }
600
Jonathan Hart612651f2019-11-25 09:21:43 -0800601 public void radiusDenied() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700602 log.warn("DENY ACCESS transition from this state is not allowed.");
603 }
604
Jonathan Hart612651f2019-11-25 09:21:43 -0800605 public void logoff() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700606 log.warn("LOGOFF transition from this state is not allowed.");
607 }
Ari Saha89831742015-06-26 10:31:48 -0700608 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700609
Ray Milkey78e95a42015-09-24 08:36:45 -0700610 /**
Jonathan Hart612651f2019-11-25 09:21:43 -0800611 * Idle state: supplicant is logged off from the network.
Ray Milkey78e95a42015-09-24 08:36:45 -0700612 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800613 static class Idle extends State {
Ray Milkey78e95a42015-09-24 08:36:45 -0700614 private final Logger log = getLogger(getClass());
615 private String name = "IDLE_STATE";
616
Shubham Sharma1e43c562019-06-19 14:18:12 +0000617 @Override
Jonathan Hart612651f2019-11-25 09:21:43 -0800618 String name() {
619 return this.name;
620 }
621
622 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700623 public void start() {
624 log.info("Moving from IDLE state to STARTED state.");
625 }
Ari Saha89831742015-06-26 10:31:48 -0700626 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700627
Ray Milkey78e95a42015-09-24 08:36:45 -0700628 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000629 * Started state: supplicant has entered the network and informed the
630 * authenticator.
Ray Milkey78e95a42015-09-24 08:36:45 -0700631 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800632 static class Started extends State {
Ray Milkey78e95a42015-09-24 08:36:45 -0700633 private final Logger log = getLogger(getClass());
634 private String name = "STARTED_STATE";
635
Shubham Sharma1e43c562019-06-19 14:18:12 +0000636 @Override
Jonathan Hart612651f2019-11-25 09:21:43 -0800637 String name() {
638 return this.name;
639 }
640
641 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700642 public void requestAccess() {
643 log.info("Moving from STARTED state to PENDING state.");
644 }
Ari Saha89831742015-06-26 10:31:48 -0700645 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700646
Ray Milkey78e95a42015-09-24 08:36:45 -0700647 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000648 * Pending state: supplicant has been identified by the authenticator but has
649 * not access yet.
Ray Milkey78e95a42015-09-24 08:36:45 -0700650 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800651 static class Pending extends State {
Ray Milkey78e95a42015-09-24 08:36:45 -0700652 private final Logger log = getLogger(getClass());
653 private String name = "PENDING_STATE";
654
Shubham Sharma1e43c562019-06-19 14:18:12 +0000655 @Override
Jonathan Hart612651f2019-11-25 09:21:43 -0800656 String name() {
657 return this.name;
658 }
659
660 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700661 public void radiusAccepted() {
662 log.info("Moving from PENDING state to AUTHORIZED state.");
663 }
664
Shubham Sharma1e43c562019-06-19 14:18:12 +0000665 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700666 public void radiusDenied() {
667 log.info("Moving from PENDING state to UNAUTHORIZED state.");
668 }
Ari Saha89831742015-06-26 10:31:48 -0700669 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700670
Ray Milkey78e95a42015-09-24 08:36:45 -0700671 /**
672 * Authorized state: supplicant port has been accepted, access is granted.
673 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800674 static class Authorized extends State {
Ray Milkey78e95a42015-09-24 08:36:45 -0700675 private final Logger log = getLogger(getClass());
676 private String name = "AUTHORIZED_STATE";
Ari Saha89831742015-06-26 10:31:48 -0700677
Shubham Sharma1e43c562019-06-19 14:18:12 +0000678 @Override
Jonathan Hart612651f2019-11-25 09:21:43 -0800679 String name() {
680 return this.name;
681 }
682
683 @Override
Qianqian Hu0c349812016-02-15 17:25:22 +0800684 public void start() {
685 log.info("Moving from AUTHORIZED state to STARTED state.");
686 }
687
Shubham Sharma1e43c562019-06-19 14:18:12 +0000688 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700689 public void logoff() {
Ari Saha89831742015-06-26 10:31:48 -0700690
Ray Milkey78e95a42015-09-24 08:36:45 -0700691 log.info("Moving from AUTHORIZED state to IDLE state.");
692 }
Ari Saha89831742015-06-26 10:31:48 -0700693 }
694
Ray Milkey78e95a42015-09-24 08:36:45 -0700695 /**
696 * Unauthorized state: supplicant port has been rejected, access is denied.
697 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800698 static class Unauthorized extends State {
Ray Milkey78e95a42015-09-24 08:36:45 -0700699 private final Logger log = getLogger(getClass());
700 private String name = "UNAUTHORIZED_STATE";
701
Shubham Sharma1e43c562019-06-19 14:18:12 +0000702 @Override
Jonathan Hart612651f2019-11-25 09:21:43 -0800703 String name() {
704 return this.name;
705 }
706
707 @Override
ke han04e47f32016-10-28 14:15:43 +0800708 public void start() {
709 log.info("Moving from UNAUTHORIZED state to STARTED state.");
710 }
711
Shubham Sharma1e43c562019-06-19 14:18:12 +0000712 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700713 public void logoff() {
714 log.info("Moving from UNAUTHORIZED state to IDLE state.");
715 }
Ari Saha89831742015-06-26 10:31:48 -0700716 }
Ari Saha89831742015-06-26 10:31:48 -0700717
Jonathan Hart612651f2019-11-25 09:21:43 -0800718 private void timeout() {
719 boolean noTrafficWithinThreshold =
720 (System.currentTimeMillis() - lastPacketReceivedTime) > ((cleanupTimerTimeOutInMins * 60 * 1000) / 2);
Shubham Sharma1e43c562019-06-19 14:18:12 +0000721
Jonathan Hart612651f2019-11-25 09:21:43 -0800722 if (TIMEOUT_ELIGIBLE_STATES.contains(currentState) && noTrafficWithinThreshold) {
723 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.TIMEOUT, this.supplicantConnectpoint));
724 // If StateMachine is not eligible for cleanup yet, reschedule cleanupTimer further.
725 } else {
726 this.scheduleTimeout();
Shubham Sharma1e43c562019-06-19 14:18:12 +0000727 }
728 }
Ari Saha89831742015-06-26 10:31:48 -0700729
Ari Saha89831742015-06-26 10:31:48 -0700730}