blob: 1b5613c469ecb852f5f0266360e25b01175b82d3 [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;
Jonathan Hart9d1ce802020-01-28 10:45:08 -080023import org.opencord.aaa.AuthenticationRecord;
Matteo Scandolocf847b82019-04-26 15:00:00 -070024import org.opencord.aaa.StateMachineDelegate;
Ari Saha89831742015-06-26 10:31:48 -070025import org.slf4j.Logger;
Thomas Vachuskae9894202015-07-30 11:59:07 -070026
Shubham Sharma4900ce62019-06-19 14:18:50 +000027import java.util.HashSet;
Shubham Sharma4900ce62019-06-19 14:18:50 +000028import java.util.Set;
Jonathan Hart612651f2019-11-25 09:21:43 -080029import java.util.concurrent.ScheduledExecutorService;
30import java.util.concurrent.TimeUnit;
Shubham Sharma4900ce62019-06-19 14:18:50 +000031
32import static org.slf4j.LoggerFactory.getLogger;
Ari Saha89831742015-06-26 10:31:48 -070033
34/**
35 * AAA Finite State Machine.
36 */
Carmelo Cascone58b53292019-09-30 12:35:31 -070037public class StateMachine {
Ari Saha89831742015-06-26 10:31:48 -070038 //INDEX to identify the state in the transition table
39 static final int STATE_IDLE = 0;
40 static final int STATE_STARTED = 1;
41 static final int STATE_PENDING = 2;
42 static final int STATE_AUTHORIZED = 3;
43 static final int STATE_UNAUTHORIZED = 4;
44
Shubham Sharma1e43c562019-06-19 14:18:12 +000045 // Defining the states where timeout can happen
Jonathan Hart612651f2019-11-25 09:21:43 -080046 static final Set<Integer> TIMEOUT_ELIGIBLE_STATES = new HashSet<>();
Shubham Sharma1e43c562019-06-19 14:18:12 +000047 static {
48 TIMEOUT_ELIGIBLE_STATES.add(STATE_STARTED);
49 TIMEOUT_ELIGIBLE_STATES.add(STATE_PENDING);
50 }
51 // INDEX to identify the transition in the transition table
Ari Saha89831742015-06-26 10:31:48 -070052 static final int TRANSITION_START = 0; // --> started
53 static final int TRANSITION_REQUEST_ACCESS = 1;
54 static final int TRANSITION_AUTHORIZE_ACCESS = 2;
55 static final int TRANSITION_DENY_ACCESS = 3;
56 static final int TRANSITION_LOGOFF = 4;
57
Jonathan Hart612651f2019-11-25 09:21:43 -080058 private static int identifier = -1;
Ari Saha89831742015-06-26 10:31:48 -070059 private byte challengeIdentifier;
60 private byte[] challengeState;
61 private byte[] username;
62 private byte[] requestAuthenticator;
63
64 // Supplicant connectivity info
Ray Milkeyf61a24e2015-09-24 16:34:02 -070065 private ConnectPoint supplicantConnectpoint;
66 private MacAddress supplicantAddress;
67 private short vlanId;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010068 private byte priorityCode;
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +000069 private long sessionStartTime;
70 private String eapolTypeVal;
71
72 public enum EapolType {
73 EAPOL_PACKET("EAPOL_PACKET"),
74 EAPOL_START("EAPOL_START"),
75 EAPOL_LOGOFF("EAPOL_LOGOFF"),
76 EAPOL_KEY("EAPOL_KEY"),
77 EAPOL_ASF("EAPOL_ASF");
78
79 private final String eaptype;
80
81 private EapolType(String value) {
82 this.eaptype = value;
83 }
84 };
85
86 private String sessionTerminateReason;
87
88 public enum SessionTerminationReasons {
89 SUPPLICANT_LOGOFF("SUPPLICANT_LOGOFF"),
90 TIME_OUT("TIME_OUT"),
Girish Kumar064084c2020-02-04 08:32:46 +000091 PORT_REMOVED("PORT_REMOVED"),
92 DEVICE_REMOVED("DEVICE_REMOVED");
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +000093
94 private final String reason;
95
96 private SessionTerminationReasons(String value) {
97 this.reason = value;
98 }
99
100 public String getReason() {
101 return this.reason;
102 }
103 };
104
105 // Supplicant packet count
106 private int totalPacketsSent;
107 private int totalPacketsReceived;
108 private int totalOctetSent;
109 private int totalOctetReceived;
Ari Saha89831742015-06-26 10:31:48 -0700110
Shubham Sharma1e43c562019-06-19 14:18:12 +0000111 // Boolean flag indicating whether response is pending from AAA Server.
112 // Used for counting timeout happening for AAA Sessions due to no response.
113 private boolean waitingForRadiusResponse;
114
115 private static int cleanupTimerTimeOutInMins;
116
Ari Saha89831742015-06-26 10:31:48 -0700117 private String sessionId = null;
118
119 private final Logger log = getLogger(getClass());
120
Shubham Sharma1e43c562019-06-19 14:18:12 +0000121 private State[] states = {new Idle(), new Started(), new Pending(), new Authorized(), new Unauthorized() };
Ari Saha89831742015-06-26 10:31:48 -0700122
Shubham Sharma1e43c562019-06-19 14:18:12 +0000123 // Cleanup Timer instance created for this session
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700124 private ScheduledExecutorService timeoutExecutor;
Shubham Sharma1e43c562019-06-19 14:18:12 +0000125 private java.util.concurrent.ScheduledFuture<?> cleanupTimer = null;
Ari Saha89831742015-06-26 10:31:48 -0700126
Shubham Sharma1e43c562019-06-19 14:18:12 +0000127 // TimeStamp of last EAPOL or RADIUS message received.
128 private long lastPacketReceivedTime = 0;
129
130 // State transition table
Ari Saha89831742015-06-26 10:31:48 -0700131 /*
Shubham Sharma1e43c562019-06-19 14:18:12 +0000132 *
133 * state IDLE | STARTED | PENDING | AUTHORIZED | UNAUTHORIZED //// input
134 * -----------------------------------------------------------------------------
135 * -----------------------
136 *
137 * START STARTED | _ | _ | STARTED | STARTED
138 *
139 * REQUEST_ACCESS _ | PENDING | _ | _ | _
140 *
141 * AUTHORIZE_ACCESS _ | _ | AUTHORIZED | _ | _
142 *
143 * DENY_ACCESS _ | - | UNAUTHORIZED | _ | _
144 *
145 * LOGOFF _ | _ | _ | IDLE | IDLE
Ari Saha89831742015-06-26 10:31:48 -0700146 */
147
Shubham Sharma1e43c562019-06-19 14:18:12 +0000148 private int[] idleTransition = {STATE_STARTED, STATE_IDLE, STATE_IDLE, STATE_IDLE, STATE_IDLE };
149 private int[] startedTransition = {STATE_STARTED, STATE_PENDING, STATE_STARTED, STATE_STARTED, STATE_STARTED };
150 private int[] pendingTransition = {STATE_PENDING, STATE_PENDING, STATE_AUTHORIZED, STATE_UNAUTHORIZED,
151 STATE_PENDING };
152 private int[] authorizedTransition = {STATE_STARTED, STATE_AUTHORIZED, STATE_AUTHORIZED, STATE_AUTHORIZED,
153 STATE_IDLE };
154 private int[] unauthorizedTransition = {STATE_STARTED, STATE_UNAUTHORIZED, STATE_UNAUTHORIZED, STATE_UNAUTHORIZED,
155 STATE_IDLE };
Ari Saha89831742015-06-26 10:31:48 -0700156
Shubham Sharma1e43c562019-06-19 14:18:12 +0000157 // THE TRANSITION TABLE
158 private int[][] transition = {idleTransition, startedTransition, pendingTransition, authorizedTransition,
159 unauthorizedTransition };
Ari Saha89831742015-06-26 10:31:48 -0700160
161 private int currentState = STATE_IDLE;
162
Jonathan Hart5db44532018-07-12 18:13:54 -0700163 private static StateMachineDelegate delegate;
164
Matteo Scandolocf847b82019-04-26 15:00:00 -0700165 public static void setDelegate(StateMachineDelegate delegate) {
166 StateMachine.delegate = delegate;
Jonathan Hart5db44532018-07-12 18:13:54 -0700167 }
168
Shubham Sharma1e43c562019-06-19 14:18:12 +0000169 public static void setcleanupTimerTimeOutInMins(int cleanupTimerTimeoutInMins) {
170 cleanupTimerTimeOutInMins = cleanupTimerTimeoutInMins;
171 }
172
Jonathan Hart612651f2019-11-25 09:21:43 -0800173 private void scheduleTimeout() {
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700174 cleanupTimer = timeoutExecutor.schedule(this::timeout, cleanupTimerTimeOutInMins, TimeUnit.MINUTES);
Jonathan Hart612651f2019-11-25 09:21:43 -0800175 }
176
Jonathan Hart5db44532018-07-12 18:13:54 -0700177 public static void unsetDelegate(StateMachineDelegate delegate) {
178 if (StateMachine.delegate == delegate) {
179 StateMachine.delegate = null;
180 }
181 }
182
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100183 public static void deleteStateMachineMapping(StateMachine machine) {
Shubham Sharma1e43c562019-06-19 14:18:12 +0000184 if (machine.cleanupTimer != null) {
185 machine.cleanupTimer.cancel(false);
186 machine.cleanupTimer = null;
187 }
188 }
189
Jonathan Hart612651f2019-11-25 09:21:43 -0800190 public void stop() {
191 if (cleanupTimer != null) {
192 cleanupTimer.cancel(false);
193 }
Shubham Sharma1e43c562019-06-19 14:18:12 +0000194 }
195
196 public boolean isWaitingForRadiusResponse() {
197 return waitingForRadiusResponse;
198 }
199
200 public void setWaitingForRadiusResponse(boolean waitingForRadiusResponse) {
201 this.waitingForRadiusResponse = waitingForRadiusResponse;
202 }
203
David K. Bainbridge62019492017-07-28 17:02:10 -0700204 /**
Jonathan Hart932bedc2018-07-12 13:46:09 -0700205 * Creates a new StateMachine with the given session ID.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700206 *
Shubham Sharma1e43c562019-06-19 14:18:12 +0000207 * @param sessionId session Id represented by the switch dpid + port number
Jonathan Hart612651f2019-11-25 09:21:43 -0800208 * @param executor executor to run background tasks on
Ari Saha89831742015-06-26 10:31:48 -0700209 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800210 public StateMachine(String sessionId, ScheduledExecutorService executor) {
Jonathan Hart932bedc2018-07-12 13:46:09 -0700211 log.info("Creating a new state machine for {}", sessionId);
Ari Saha89831742015-06-26 10:31:48 -0700212 this.sessionId = sessionId;
Matteo Scandolo9510e5d2020-09-24 17:31:52 -0700213 this.timeoutExecutor = executor;
Ari Saha89831742015-06-26 10:31:48 -0700214 }
215
216 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700217 * Gets the connect point for the supplicant side.
218 *
219 * @return supplicant connect point
220 */
221 public ConnectPoint supplicantConnectpoint() {
222 return supplicantConnectpoint;
223 }
224
225 /**
226 * Sets the supplicant side connect point.
227 *
228 * @param supplicantConnectpoint supplicant select point.
229 */
230 public void setSupplicantConnectpoint(ConnectPoint supplicantConnectpoint) {
231 this.supplicantConnectpoint = supplicantConnectpoint;
232 }
233
234 /**
235 * Gets the MAC address of the supplicant.
236 *
237 * @return supplicant MAC address
238 */
239 public MacAddress supplicantAddress() {
240 return supplicantAddress;
241 }
242
243 /**
244 * Sets the supplicant MAC address.
245 *
246 * @param supplicantAddress new supplicant MAC address
247 */
248 public void setSupplicantAddress(MacAddress supplicantAddress) {
249 this.supplicantAddress = supplicantAddress;
250 }
251
252 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000253 * Sets the lastPacketReceivedTime.
254 *
255 * @param lastPacketReceivedTime timelastPacket was received
256 */
257 public void setLastPacketReceivedTime(long lastPacketReceivedTime) {
258 this.lastPacketReceivedTime = lastPacketReceivedTime;
259 }
260
261 /**
262 * Gets the lastPacketReceivedTime.
263 *
264 * @return lastPacketReceivedTime
265 */
266 public long getLastPacketReceivedTime() {
267 return lastPacketReceivedTime;
268 }
269
270 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700271 * Gets the client's Vlan ID.
272 *
273 * @return client vlan ID
274 */
275 public short vlanId() {
276 return vlanId;
277 }
278
279 /**
280 * Sets the client's vlan ID.
281 *
282 * @param vlanId new client vlan ID
283 */
284 public void setVlanId(short vlanId) {
285 this.vlanId = vlanId;
286 }
287
288 /**
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100289 * Gets the client's priority Code.
290 *
291 * @return client Priority code
292 */
293 public byte priorityCode() {
294 return priorityCode;
295 }
296
297 /**
298 * Sets the client's priority Code.
299 *
300 * @param priorityCode new client priority Code
301 */
302 public void setPriorityCode(byte priorityCode) {
303 this.priorityCode = priorityCode;
304 }
305
306 /**
Kartikey Dubeyadeb26e2019-10-01 12:18:35 +0000307 * Gets the session start time.
308 *
309 * @return session start time
310 */
311 public long sessionStartTime() {
312 return sessionStartTime;
313 }
314
315 /**
316 * Sets the session start time.
317 *
318 * @param sessionStartTime new session start time
319 */
320 public void setSessionStartTime(long sessionStartTime) {
321 this.sessionStartTime = sessionStartTime;
322 }
323
324 /**
325 * returns eapol Type.
326 *
327 * @return eapolTypeVal.
328 */
329 public String eapolType() {
330 return this.eapolTypeVal;
331 }
332
333 /**
334 * Sets eapol Type name from eapol value.
335 *
336 * @param value eapol type as byte.
337 */
338 public void setEapolTypeVal(byte value) {
339 switch (value) {
340 case (byte) 0: this.eapolTypeVal = EapolType.EAPOL_PACKET.eaptype;
341 break;
342 case (byte) 1: this.eapolTypeVal = EapolType.EAPOL_START.eaptype;
343 break;
344 case (byte) 2: this.eapolTypeVal = EapolType.EAPOL_LOGOFF.eaptype;
345 break;
346 case (byte) 3: this.eapolTypeVal = EapolType.EAPOL_KEY.eaptype;
347 break;
348 case (byte) 4: this.eapolTypeVal = EapolType.EAPOL_ASF.eaptype;
349 break;
350 default : this.eapolTypeVal = "INVALID TYPE";
351 }
352 }
353
354 public String getSessionTerminateReason() {
355 return sessionTerminateReason;
356 }
357
358 public void setSessionTerminateReason(String sessionTerminateReason) {
359 this.sessionTerminateReason = sessionTerminateReason;
360 }
361
362 public int totalPacketsReceived() {
363 return this.totalPacketsReceived;
364 }
365
366 public void incrementTotalPacketsReceived() {
367 this.totalPacketsReceived = this.totalPacketsReceived + 1;
368 }
369
370 public int totalPacketsSent() {
371 return this.totalPacketsSent;
372 }
373
374 public void incrementTotalPacketsSent() {
375 this.totalPacketsSent = this.totalPacketsSent + 1;
376 }
377
378 public void incrementTotalOctetReceived(short packetLen) {
379 this.totalOctetReceived = this.totalOctetReceived + packetLen;
380 }
381
382 public void incrementTotalOctetSent(short packetLen) {
383 this.totalOctetSent = this.totalOctetSent + packetLen;
384 }
385
386 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700387 * Gets the client id that is requesting for access.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700388 *
Ari Saha89831742015-06-26 10:31:48 -0700389 * @return The client id.
390 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700391 public String sessionId() {
Ari Saha89831742015-06-26 10:31:48 -0700392 return this.sessionId;
393 }
394
395 /**
Ari Saha89831742015-06-26 10:31:48 -0700396 * Set the challenge identifier and the state issued by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700397 *
Shubham Sharma1e43c562019-06-19 14:18:12 +0000398 * @param challengeIdentifier The challenge identifier set into the EAP packet
399 * from the RADIUS message.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700400 * @param challengeState The challenge state from the RADIUS.
Ari Saha89831742015-06-26 10:31:48 -0700401 */
402 protected void setChallengeInfo(byte challengeIdentifier, byte[] challengeState) {
403 this.challengeIdentifier = challengeIdentifier;
404 this.challengeState = challengeState;
405 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700406
Ari Saha89831742015-06-26 10:31:48 -0700407 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000408 * Set the challenge identifier issued by the RADIUS on the access challenge
409 * request.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700410 *
Shubham Sharma1e43c562019-06-19 14:18:12 +0000411 * @param challengeIdentifier The challenge identifier set into the EAP packet
412 * from the RADIUS message.
Ari Saha89831742015-06-26 10:31:48 -0700413 */
414 protected void setChallengeIdentifier(byte challengeIdentifier) {
415 log.info("Set Challenge Identifier to {}", challengeIdentifier);
416 this.challengeIdentifier = challengeIdentifier;
417 }
418
419 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700420 * Gets the challenge EAP identifier set by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700421 *
Ari Saha89831742015-06-26 10:31:48 -0700422 * @return The challenge EAP identifier.
423 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700424 protected byte challengeIdentifier() {
Ari Saha89831742015-06-26 10:31:48 -0700425 return this.challengeIdentifier;
426 }
427
Ari Saha89831742015-06-26 10:31:48 -0700428 /**
429 * Set the challenge state info issued by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700430 *
Ari Saha89831742015-06-26 10:31:48 -0700431 * @param challengeState The challenge state from the RADIUS.
432 */
433 protected void setChallengeState(byte[] challengeState) {
434 log.info("Set Challenge State");
435 this.challengeState = challengeState;
436 }
437
438 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700439 * Gets the challenge state set by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700440 *
Ari Saha89831742015-06-26 10:31:48 -0700441 * @return The challenge state.
442 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700443 protected byte[] challengeState() {
Ari Saha89831742015-06-26 10:31:48 -0700444 return this.challengeState;
445 }
446
447 /**
448 * Set the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700449 *
Ari Saha89831742015-06-26 10:31:48 -0700450 * @param username The username sent to the RADIUS upon access request.
451 */
452 protected void setUsername(byte[] username) {
453 this.username = username;
454 }
455
Ari Saha89831742015-06-26 10:31:48 -0700456 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700457 * Gets the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700458 *
Ari Saha89831742015-06-26 10:31:48 -0700459 * @return The requestAuthenticator.
460 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700461 protected byte[] requestAuthenticator() {
Ari Saha89831742015-06-26 10:31:48 -0700462 return this.requestAuthenticator;
463 }
464
465 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700466 * Sets the authenticator.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700467 *
Ari Saha89831742015-06-26 10:31:48 -0700468 * @param authenticator The username sent to the RADIUS upon access request.
469 */
470 protected void setRequestAuthenticator(byte[] authenticator) {
471 this.requestAuthenticator = authenticator;
472 }
473
Ari Saha89831742015-06-26 10:31:48 -0700474 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700475 * Gets the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700476 *
Ari Saha89831742015-06-26 10:31:48 -0700477 * @return The username.
478 */
Carmelo Cascone58b53292019-09-30 12:35:31 -0700479 public byte[] username() {
Ari Saha89831742015-06-26 10:31:48 -0700480 return this.username;
481 }
482
483 /**
484 * Return the identifier of the state machine.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700485 *
Ari Saha89831742015-06-26 10:31:48 -0700486 * @return The state machine identifier.
487 */
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100488 public synchronized byte identifier() {
Jonathan Hart612651f2019-11-25 09:21:43 -0800489 identifier = (identifier + 1) % 255;
490 return (byte) identifier;
Ari Saha89831742015-06-26 10:31:48 -0700491 }
492
Ari Saha89831742015-06-26 10:31:48 -0700493 /**
494 * Move to the next state.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700495 *
Ray Milkey78e95a42015-09-24 08:36:45 -0700496 * @param msg message
Ari Saha89831742015-06-26 10:31:48 -0700497 */
Thomas Vachuskae9894202015-07-30 11:59:07 -0700498 private void next(int msg) {
Ari Saha89831742015-06-26 10:31:48 -0700499 currentState = transition[currentState][msg];
500 log.info("Current State " + currentState);
501 }
502
503 /**
504 * Client has requested the start action to allow network access.
505 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800506 public void start() {
507 this.scheduleTimeout();
508
Ray Milkey78e95a42015-09-24 08:36:45 -0700509 states[currentState].start();
Jonathan Hart5db44532018-07-12 18:13:54 -0700510
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800511 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.STARTED,
512 supplicantConnectpoint, toAuthRecord()));
Jonathan Hart5db44532018-07-12 18:13:54 -0700513
Shubham Sharma1e43c562019-06-19 14:18:12 +0000514 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700515 next(TRANSITION_START);
Ari Saha89831742015-06-26 10:31:48 -0700516 }
517
518 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000519 * An Identification information has been sent by the supplicant. Move to the
520 * next state if possible.
Ari Saha89831742015-06-26 10:31:48 -0700521 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800522 public void requestAccess() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700523 states[currentState].requestAccess();
Jonathan Hart5db44532018-07-12 18:13:54 -0700524
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800525 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.REQUESTED,
526 supplicantConnectpoint, toAuthRecord()));
Jonathan Hart5db44532018-07-12 18:13:54 -0700527
Shubham Sharma1e43c562019-06-19 14:18:12 +0000528 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700529 next(TRANSITION_REQUEST_ACCESS);
Ari Saha89831742015-06-26 10:31:48 -0700530 }
531
532 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000533 * RADIUS has accepted the identification. Move to the next state if possible.
Ari Saha89831742015-06-26 10:31:48 -0700534 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800535 public void authorizeAccess() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700536 states[currentState].radiusAccepted();
Shubham Sharma1e43c562019-06-19 14:18:12 +0000537 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700538 next(TRANSITION_AUTHORIZE_ACCESS);
Ari Saha89831742015-06-26 10:31:48 -0700539
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800540 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.APPROVED,
541 supplicantConnectpoint, toAuthRecord()));
Ari Saha89831742015-06-26 10:31:48 -0700542
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100543 // Clear mapping
544 deleteStateMachineMapping(this);
Ari Saha89831742015-06-26 10:31:48 -0700545 }
546
547 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000548 * RADIUS has denied the identification. Move to the next state if possible.
Ari Saha89831742015-06-26 10:31:48 -0700549 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800550 public void denyAccess() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700551 states[currentState].radiusDenied();
Shubham Sharma1e43c562019-06-19 14:18:12 +0000552 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700553 next(TRANSITION_DENY_ACCESS);
Jonathan Hart5db44532018-07-12 18:13:54 -0700554
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800555 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.DENIED,
556 supplicantConnectpoint, toAuthRecord()));
Jonathan Hart5db44532018-07-12 18:13:54 -0700557
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100558 // Clear mappings
559 deleteStateMachineMapping(this);
Ari Saha89831742015-06-26 10:31:48 -0700560 }
561
562 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000563 * Logoff request has been requested. Move to the next state if possible.
Ari Saha89831742015-06-26 10:31:48 -0700564 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800565 public void logoff() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700566 states[currentState].logoff();
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800567
568 // TODO event here?
569
Shubham Sharma1e43c562019-06-19 14:18:12 +0000570 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700571 next(TRANSITION_LOGOFF);
Ari Saha89831742015-06-26 10:31:48 -0700572 }
573
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800574 private AuthenticationRecord toAuthRecord() {
575 return new AuthenticationRecord(this.supplicantConnectpoint(),
576 this.username(), this.supplicantAddress(), this.stateString(),
577 this.getLastPacketReceivedTime());
578 }
579
Ari Saha89831742015-06-26 10:31:48 -0700580 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700581 * Gets the current state.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700582 *
Shubham Sharma1e43c562019-06-19 14:18:12 +0000583 * @return The current state. Could be STATE_IDLE, STATE_STARTED, STATE_PENDING,
584 * STATE_AUTHORIZED, STATE_UNAUTHORIZED.
Ari Saha89831742015-06-26 10:31:48 -0700585 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700586 public int state() {
Ari Saha89831742015-06-26 10:31:48 -0700587 return currentState;
588 }
589
Jonathan Hart612651f2019-11-25 09:21:43 -0800590 public String stateString() {
591 return states[currentState].name();
Ari Saha89831742015-06-26 10:31:48 -0700592 }
Ari Saha89831742015-06-26 10:31:48 -0700593
Jonathan Hart612651f2019-11-25 09:21:43 -0800594 @Override
595 public String toString() {
596 return ("sessionId: " + this.sessionId) + "\t" + ("state: " + this.currentState);
597 }
598
599 abstract static class State {
Ray Milkey78e95a42015-09-24 08:36:45 -0700600 private final Logger log = getLogger(getClass());
Thomas Vachuskae9894202015-07-30 11:59:07 -0700601
Jonathan Hart612651f2019-11-25 09:21:43 -0800602 abstract String name();
Ari Saha89831742015-06-26 10:31:48 -0700603
Jonathan Hart612651f2019-11-25 09:21:43 -0800604 public void start() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700605 log.warn("START transition from this state is not allowed.");
606 }
Ari Saha89831742015-06-26 10:31:48 -0700607
Jonathan Hart612651f2019-11-25 09:21:43 -0800608 public void requestAccess() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700609 log.warn("REQUEST ACCESS transition from this state is not allowed.");
610 }
611
Jonathan Hart612651f2019-11-25 09:21:43 -0800612 public void radiusAccepted() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700613 log.warn("AUTHORIZE ACCESS transition from this state is not allowed.");
614 }
615
Jonathan Hart612651f2019-11-25 09:21:43 -0800616 public void radiusDenied() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700617 log.warn("DENY ACCESS transition from this state is not allowed.");
618 }
619
Jonathan Hart612651f2019-11-25 09:21:43 -0800620 public void logoff() {
Ray Milkey78e95a42015-09-24 08:36:45 -0700621 log.warn("LOGOFF transition from this state is not allowed.");
622 }
Ari Saha89831742015-06-26 10:31:48 -0700623 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700624
Ray Milkey78e95a42015-09-24 08:36:45 -0700625 /**
Jonathan Hart612651f2019-11-25 09:21:43 -0800626 * Idle state: supplicant is logged off from the network.
Ray Milkey78e95a42015-09-24 08:36:45 -0700627 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800628 static class Idle extends State {
Ray Milkey78e95a42015-09-24 08:36:45 -0700629 private final Logger log = getLogger(getClass());
630 private String name = "IDLE_STATE";
631
Shubham Sharma1e43c562019-06-19 14:18:12 +0000632 @Override
Jonathan Hart612651f2019-11-25 09:21:43 -0800633 String name() {
634 return this.name;
635 }
636
637 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700638 public void start() {
639 log.info("Moving from IDLE state to STARTED state.");
640 }
Ari Saha89831742015-06-26 10:31:48 -0700641 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700642
Ray Milkey78e95a42015-09-24 08:36:45 -0700643 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000644 * Started state: supplicant has entered the network and informed the
645 * authenticator.
Ray Milkey78e95a42015-09-24 08:36:45 -0700646 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800647 static class Started extends State {
Ray Milkey78e95a42015-09-24 08:36:45 -0700648 private final Logger log = getLogger(getClass());
649 private String name = "STARTED_STATE";
650
Shubham Sharma1e43c562019-06-19 14:18:12 +0000651 @Override
Jonathan Hart612651f2019-11-25 09:21:43 -0800652 String name() {
653 return this.name;
654 }
655
656 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700657 public void requestAccess() {
658 log.info("Moving from STARTED state to PENDING state.");
659 }
Ari Saha89831742015-06-26 10:31:48 -0700660 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700661
Ray Milkey78e95a42015-09-24 08:36:45 -0700662 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000663 * Pending state: supplicant has been identified by the authenticator but has
664 * not access yet.
Ray Milkey78e95a42015-09-24 08:36:45 -0700665 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800666 static class Pending extends State {
Ray Milkey78e95a42015-09-24 08:36:45 -0700667 private final Logger log = getLogger(getClass());
668 private String name = "PENDING_STATE";
669
Shubham Sharma1e43c562019-06-19 14:18:12 +0000670 @Override
Jonathan Hart612651f2019-11-25 09:21:43 -0800671 String name() {
672 return this.name;
673 }
674
675 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700676 public void radiusAccepted() {
677 log.info("Moving from PENDING state to AUTHORIZED state.");
678 }
679
Shubham Sharma1e43c562019-06-19 14:18:12 +0000680 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700681 public void radiusDenied() {
682 log.info("Moving from PENDING state to UNAUTHORIZED state.");
683 }
Ari Saha89831742015-06-26 10:31:48 -0700684 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700685
Ray Milkey78e95a42015-09-24 08:36:45 -0700686 /**
687 * Authorized state: supplicant port has been accepted, access is granted.
688 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800689 static class Authorized extends State {
Ray Milkey78e95a42015-09-24 08:36:45 -0700690 private final Logger log = getLogger(getClass());
691 private String name = "AUTHORIZED_STATE";
Ari Saha89831742015-06-26 10:31:48 -0700692
Shubham Sharma1e43c562019-06-19 14:18:12 +0000693 @Override
Jonathan Hart612651f2019-11-25 09:21:43 -0800694 String name() {
695 return this.name;
696 }
697
698 @Override
Qianqian Hu0c349812016-02-15 17:25:22 +0800699 public void start() {
700 log.info("Moving from AUTHORIZED state to STARTED state.");
701 }
702
Shubham Sharma1e43c562019-06-19 14:18:12 +0000703 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700704 public void logoff() {
Ari Saha89831742015-06-26 10:31:48 -0700705
Ray Milkey78e95a42015-09-24 08:36:45 -0700706 log.info("Moving from AUTHORIZED state to IDLE state.");
707 }
Ari Saha89831742015-06-26 10:31:48 -0700708 }
709
Ray Milkey78e95a42015-09-24 08:36:45 -0700710 /**
711 * Unauthorized state: supplicant port has been rejected, access is denied.
712 */
Jonathan Hart612651f2019-11-25 09:21:43 -0800713 static class Unauthorized extends State {
Ray Milkey78e95a42015-09-24 08:36:45 -0700714 private final Logger log = getLogger(getClass());
715 private String name = "UNAUTHORIZED_STATE";
716
Shubham Sharma1e43c562019-06-19 14:18:12 +0000717 @Override
Jonathan Hart612651f2019-11-25 09:21:43 -0800718 String name() {
719 return this.name;
720 }
721
722 @Override
ke han04e47f32016-10-28 14:15:43 +0800723 public void start() {
724 log.info("Moving from UNAUTHORIZED state to STARTED state.");
725 }
726
Shubham Sharma1e43c562019-06-19 14:18:12 +0000727 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700728 public void logoff() {
729 log.info("Moving from UNAUTHORIZED state to IDLE state.");
730 }
Ari Saha89831742015-06-26 10:31:48 -0700731 }
Ari Saha89831742015-06-26 10:31:48 -0700732
Jonathan Hart612651f2019-11-25 09:21:43 -0800733 private void timeout() {
734 boolean noTrafficWithinThreshold =
735 (System.currentTimeMillis() - lastPacketReceivedTime) > ((cleanupTimerTimeOutInMins * 60 * 1000) / 2);
Shubham Sharma1e43c562019-06-19 14:18:12 +0000736
Jonathan Hart612651f2019-11-25 09:21:43 -0800737 if (TIMEOUT_ELIGIBLE_STATES.contains(currentState) && noTrafficWithinThreshold) {
Jonathan Hart9d1ce802020-01-28 10:45:08 -0800738 this.setSessionTerminateReason(SessionTerminationReasons.TIME_OUT.reason);
739
740 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.TIMEOUT,
741 this.supplicantConnectpoint));
Jonathan Hart612651f2019-11-25 09:21:43 -0800742 // If StateMachine is not eligible for cleanup yet, reschedule cleanupTimer further.
743 } else {
744 this.scheduleTimeout();
Shubham Sharma1e43c562019-06-19 14:18:12 +0000745 }
746 }
Ari Saha89831742015-06-26 10:31:48 -0700747
Ari Saha89831742015-06-26 10:31:48 -0700748}