blob: 5e9e14028c25b08f20c7bac5f7832f892aeeb0b6 [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
Shubham Sharma1e43c562019-06-19 14:18:12 +000020import static org.slf4j.LoggerFactory.getLogger;
21
22import java.util.HashSet;
23import java.util.Map;
24import java.util.Set;
25
Ari Saha89831742015-06-26 10:31:48 -070026import org.onlab.packet.MacAddress;
27import org.onosproject.net.ConnectPoint;
Matteo Scandolocf847b82019-04-26 15:00:00 -070028import org.opencord.aaa.AuthenticationEvent;
29import org.opencord.aaa.StateMachineDelegate;
Ari Saha89831742015-06-26 10:31:48 -070030import org.slf4j.Logger;
Thomas Vachuskae9894202015-07-30 11:59:07 -070031
Shubham Sharma1e43c562019-06-19 14:18:12 +000032import com.google.common.collect.Maps;
Ari Saha89831742015-06-26 10:31:48 -070033
34/**
35 * AAA Finite State Machine.
36 */
37
Carmelo Cascone58b53292019-09-30 12:35:31 -070038public class StateMachine {
Ari Saha89831742015-06-26 10:31:48 -070039 //INDEX to identify the state in the transition table
40 static final int STATE_IDLE = 0;
41 static final int STATE_STARTED = 1;
42 static final int STATE_PENDING = 2;
43 static final int STATE_AUTHORIZED = 3;
44 static final int STATE_UNAUTHORIZED = 4;
45
Shubham Sharma1e43c562019-06-19 14:18:12 +000046 // Defining the states where timeout can happen
47 static final Set<Integer> TIMEOUT_ELIGIBLE_STATES = new HashSet();
48 static {
49 TIMEOUT_ELIGIBLE_STATES.add(STATE_STARTED);
50 TIMEOUT_ELIGIBLE_STATES.add(STATE_PENDING);
51 }
52 // INDEX to identify the transition in the transition table
Ari Saha89831742015-06-26 10:31:48 -070053 static final int TRANSITION_START = 0; // --> started
54 static final int TRANSITION_REQUEST_ACCESS = 1;
55 static final int TRANSITION_AUTHORIZE_ACCESS = 2;
56 static final int TRANSITION_DENY_ACCESS = 3;
57 static final int TRANSITION_LOGOFF = 4;
58
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010059 private static int identifier = -1;
Ari Saha89831742015-06-26 10:31:48 -070060 private byte challengeIdentifier;
61 private byte[] challengeState;
62 private byte[] username;
63 private byte[] requestAuthenticator;
64
65 // Supplicant connectivity info
Ray Milkeyf61a24e2015-09-24 16:34:02 -070066 private ConnectPoint supplicantConnectpoint;
67 private MacAddress supplicantAddress;
68 private short vlanId;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010069 private byte priorityCode;
Ari Saha89831742015-06-26 10:31:48 -070070
Shubham Sharma1e43c562019-06-19 14:18:12 +000071 // Boolean flag indicating whether response is pending from AAA Server.
72 // Used for counting timeout happening for AAA Sessions due to no response.
73 private boolean waitingForRadiusResponse;
74
75 private static int cleanupTimerTimeOutInMins;
76
Ari Saha89831742015-06-26 10:31:48 -070077 private String sessionId = null;
78
79 private final Logger log = getLogger(getClass());
80
Shubham Sharma1e43c562019-06-19 14:18:12 +000081 private State[] states = {new Idle(), new Started(), new Pending(), new Authorized(), new Unauthorized() };
Ari Saha89831742015-06-26 10:31:48 -070082
Shubham Sharma1e43c562019-06-19 14:18:12 +000083 // Cleanup Timer instance created for this session
84 private java.util.concurrent.ScheduledFuture<?> cleanupTimer = null;
Ari Saha89831742015-06-26 10:31:48 -070085
Shubham Sharma1e43c562019-06-19 14:18:12 +000086 // TimeStamp of last EAPOL or RADIUS message received.
87 private long lastPacketReceivedTime = 0;
88
89 // State transition table
Ari Saha89831742015-06-26 10:31:48 -070090 /*
Shubham Sharma1e43c562019-06-19 14:18:12 +000091 *
92 * state IDLE | STARTED | PENDING | AUTHORIZED | UNAUTHORIZED //// input
93 * -----------------------------------------------------------------------------
94 * -----------------------
95 *
96 * START STARTED | _ | _ | STARTED | STARTED
97 *
98 * REQUEST_ACCESS _ | PENDING | _ | _ | _
99 *
100 * AUTHORIZE_ACCESS _ | _ | AUTHORIZED | _ | _
101 *
102 * DENY_ACCESS _ | - | UNAUTHORIZED | _ | _
103 *
104 * LOGOFF _ | _ | _ | IDLE | IDLE
Ari Saha89831742015-06-26 10:31:48 -0700105 */
106
Shubham Sharma1e43c562019-06-19 14:18:12 +0000107 private int[] idleTransition = {STATE_STARTED, STATE_IDLE, STATE_IDLE, STATE_IDLE, STATE_IDLE };
108 private int[] startedTransition = {STATE_STARTED, STATE_PENDING, STATE_STARTED, STATE_STARTED, STATE_STARTED };
109 private int[] pendingTransition = {STATE_PENDING, STATE_PENDING, STATE_AUTHORIZED, STATE_UNAUTHORIZED,
110 STATE_PENDING };
111 private int[] authorizedTransition = {STATE_STARTED, STATE_AUTHORIZED, STATE_AUTHORIZED, STATE_AUTHORIZED,
112 STATE_IDLE };
113 private int[] unauthorizedTransition = {STATE_STARTED, STATE_UNAUTHORIZED, STATE_UNAUTHORIZED, STATE_UNAUTHORIZED,
114 STATE_IDLE };
Ari Saha89831742015-06-26 10:31:48 -0700115
Shubham Sharma1e43c562019-06-19 14:18:12 +0000116 // THE TRANSITION TABLE
117 private int[][] transition = {idleTransition, startedTransition, pendingTransition, authorizedTransition,
118 unauthorizedTransition };
Ari Saha89831742015-06-26 10:31:48 -0700119
120 private int currentState = STATE_IDLE;
121
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700122 // Maps of state machines. Each state machine is represented by an
123 // unique identifier on the switch: dpid + port number
124 private static Map<String, StateMachine> sessionIdMap;
125 private static Map<Integer, StateMachine> identifierMap;
Ari Saha89831742015-06-26 10:31:48 -0700126
Jonathan Hart5db44532018-07-12 18:13:54 -0700127 private static StateMachineDelegate delegate;
128
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700129 public static void initializeMaps() {
130 sessionIdMap = Maps.newConcurrentMap();
131 identifierMap = Maps.newConcurrentMap();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100132 identifier = -1;
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700133 }
134
135 public static void destroyMaps() {
136 sessionIdMap = null;
137 identifierMap = null;
138 }
139
Matteo Scandolocf847b82019-04-26 15:00:00 -0700140 public static void setDelegate(StateMachineDelegate delegate) {
141 StateMachine.delegate = delegate;
Jonathan Hart5db44532018-07-12 18:13:54 -0700142 }
143
Shubham Sharma1e43c562019-06-19 14:18:12 +0000144 public static void setcleanupTimerTimeOutInMins(int cleanupTimerTimeoutInMins) {
145 cleanupTimerTimeOutInMins = cleanupTimerTimeoutInMins;
146 }
147
Jonathan Hart5db44532018-07-12 18:13:54 -0700148 public static void unsetDelegate(StateMachineDelegate delegate) {
149 if (StateMachine.delegate == delegate) {
150 StateMachine.delegate = null;
151 }
152 }
153
Qianqian Hu61a6a402016-02-16 15:18:05 +0800154 public static Map<String, StateMachine> sessionIdMap() {
155 return sessionIdMap;
156 }
157
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700158 public static StateMachine lookupStateMachineById(byte identifier) {
159 return identifierMap.get((int) identifier);
160 }
161
162 public static StateMachine lookupStateMachineBySessionId(String sessionId) {
163 return sessionIdMap.get(sessionId);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100164 }
165
Shubham Sharma1e43c562019-06-19 14:18:12 +0000166 public static void deleteStateMachineId(String sessionId) {
167 sessionIdMap.remove(sessionId);
168 }
169
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100170 public static void deleteStateMachineMapping(StateMachine machine) {
171 identifierMap.entrySet().removeIf(e -> e.getValue().equals(machine));
Shubham Sharma1e43c562019-06-19 14:18:12 +0000172 if (machine.cleanupTimer != null) {
173 machine.cleanupTimer.cancel(false);
174 machine.cleanupTimer = null;
175 }
176 }
177
178 public java.util.concurrent.ScheduledFuture<?> getCleanupTimer() {
179 return cleanupTimer;
180 }
181
182 public boolean isWaitingForRadiusResponse() {
183 return waitingForRadiusResponse;
184 }
185
186 public void setWaitingForRadiusResponse(boolean waitingForRadiusResponse) {
187 this.waitingForRadiusResponse = waitingForRadiusResponse;
188 }
189
190 public void setCleanupTimer(java.util.concurrent.ScheduledFuture<?> cleanupTimer) {
191 this.cleanupTimer = cleanupTimer;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100192 }
193
194 /**
David K. Bainbridge62019492017-07-28 17:02:10 -0700195 * Deletes authentication state machine records for a given MAC address.
Shubham Sharma1e43c562019-06-19 14:18:12 +0000196 *
David K. Bainbridge62019492017-07-28 17:02:10 -0700197 * @param mac mac address of the suppliant who's state machine should be removed
198 */
199 public static void deleteByMac(MacAddress mac) {
200
201 // Walk the map from session IDs to state machines looking for a MAC match
202 for (Map.Entry<String, StateMachine> e : sessionIdMap.entrySet()) {
203
204 // If a MAC match is found then delete the entry from the session ID
205 // and identifier map as well as call delete identifier to clean up
206 // the identifier bit set.
Shubham Sharma1e43c562019-06-19 14:18:12 +0000207 if (e.getValue() != null && e.getValue().supplicantAddress != null
208 && e.getValue().supplicantAddress.equals(mac)) {
David K. Bainbridge62019492017-07-28 17:02:10 -0700209 sessionIdMap.remove(e.getValue().sessionId);
210 if (e.getValue().identifier != -1) {
211 deleteStateMachineMapping(e.getValue());
212 }
213 break;
214 }
215 }
216 }
217
218 /**
Jonathan Hart932bedc2018-07-12 13:46:09 -0700219 * Creates a new StateMachine with the given session ID.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700220 *
Shubham Sharma1e43c562019-06-19 14:18:12 +0000221 * @param sessionId session Id represented by the switch dpid + port number
Ari Saha89831742015-06-26 10:31:48 -0700222 */
Jonathan Hart932bedc2018-07-12 13:46:09 -0700223 public StateMachine(String sessionId) {
224 log.info("Creating a new state machine for {}", sessionId);
Ari Saha89831742015-06-26 10:31:48 -0700225 this.sessionId = sessionId;
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700226 sessionIdMap.put(sessionId, this);
Ari Saha89831742015-06-26 10:31:48 -0700227 }
228
229 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700230 * Gets the connect point for the supplicant side.
231 *
232 * @return supplicant connect point
233 */
234 public ConnectPoint supplicantConnectpoint() {
235 return supplicantConnectpoint;
236 }
237
238 /**
239 * Sets the supplicant side connect point.
240 *
241 * @param supplicantConnectpoint supplicant select point.
242 */
243 public void setSupplicantConnectpoint(ConnectPoint supplicantConnectpoint) {
244 this.supplicantConnectpoint = supplicantConnectpoint;
245 }
246
247 /**
248 * Gets the MAC address of the supplicant.
249 *
250 * @return supplicant MAC address
251 */
252 public MacAddress supplicantAddress() {
253 return supplicantAddress;
254 }
255
256 /**
257 * Sets the supplicant MAC address.
258 *
259 * @param supplicantAddress new supplicant MAC address
260 */
261 public void setSupplicantAddress(MacAddress supplicantAddress) {
262 this.supplicantAddress = supplicantAddress;
263 }
264
265 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000266 * Sets the lastPacketReceivedTime.
267 *
268 * @param lastPacketReceivedTime timelastPacket was received
269 */
270 public void setLastPacketReceivedTime(long lastPacketReceivedTime) {
271 this.lastPacketReceivedTime = lastPacketReceivedTime;
272 }
273
274 /**
275 * Gets the lastPacketReceivedTime.
276 *
277 * @return lastPacketReceivedTime
278 */
279 public long getLastPacketReceivedTime() {
280 return lastPacketReceivedTime;
281 }
282
283 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700284 * Gets the client's Vlan ID.
285 *
286 * @return client vlan ID
287 */
288 public short vlanId() {
289 return vlanId;
290 }
291
292 /**
293 * Sets the client's vlan ID.
294 *
295 * @param vlanId new client vlan ID
296 */
297 public void setVlanId(short vlanId) {
298 this.vlanId = vlanId;
299 }
300
301 /**
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100302 * Gets the client's priority Code.
303 *
304 * @return client Priority code
305 */
306 public byte priorityCode() {
307 return priorityCode;
308 }
309
310 /**
311 * Sets the client's priority Code.
312 *
313 * @param priorityCode new client priority Code
314 */
315 public void setPriorityCode(byte priorityCode) {
316 this.priorityCode = priorityCode;
317 }
318
319 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700320 * Gets the client id that is requesting for access.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700321 *
Ari Saha89831742015-06-26 10:31:48 -0700322 * @return The client id.
323 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700324 public String sessionId() {
Ari Saha89831742015-06-26 10:31:48 -0700325 return this.sessionId;
326 }
327
328 /**
Ari Saha89831742015-06-26 10:31:48 -0700329 * Set the challenge identifier and the state issued by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700330 *
Shubham Sharma1e43c562019-06-19 14:18:12 +0000331 * @param challengeIdentifier The challenge identifier set into the EAP packet
332 * from the RADIUS message.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700333 * @param challengeState The challenge state from the RADIUS.
Ari Saha89831742015-06-26 10:31:48 -0700334 */
335 protected void setChallengeInfo(byte challengeIdentifier, byte[] challengeState) {
336 this.challengeIdentifier = challengeIdentifier;
337 this.challengeState = challengeState;
338 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700339
Ari Saha89831742015-06-26 10:31:48 -0700340 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000341 * Set the challenge identifier issued by the RADIUS on the access challenge
342 * request.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700343 *
Shubham Sharma1e43c562019-06-19 14:18:12 +0000344 * @param challengeIdentifier The challenge identifier set into the EAP packet
345 * from the RADIUS message.
Ari Saha89831742015-06-26 10:31:48 -0700346 */
347 protected void setChallengeIdentifier(byte challengeIdentifier) {
348 log.info("Set Challenge Identifier to {}", challengeIdentifier);
349 this.challengeIdentifier = challengeIdentifier;
350 }
351
352 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700353 * Gets the challenge EAP identifier set by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700354 *
Ari Saha89831742015-06-26 10:31:48 -0700355 * @return The challenge EAP identifier.
356 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700357 protected byte challengeIdentifier() {
Ari Saha89831742015-06-26 10:31:48 -0700358 return this.challengeIdentifier;
359 }
360
Ari Saha89831742015-06-26 10:31:48 -0700361 /**
362 * Set the challenge state info issued by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700363 *
Ari Saha89831742015-06-26 10:31:48 -0700364 * @param challengeState The challenge state from the RADIUS.
365 */
366 protected void setChallengeState(byte[] challengeState) {
367 log.info("Set Challenge State");
368 this.challengeState = challengeState;
369 }
370
371 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700372 * Gets the challenge state set by the RADIUS.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700373 *
Ari Saha89831742015-06-26 10:31:48 -0700374 * @return The challenge state.
375 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700376 protected byte[] challengeState() {
Ari Saha89831742015-06-26 10:31:48 -0700377 return this.challengeState;
378 }
379
380 /**
381 * Set the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700382 *
Ari Saha89831742015-06-26 10:31:48 -0700383 * @param username The username sent to the RADIUS upon access request.
384 */
385 protected void setUsername(byte[] username) {
386 this.username = username;
387 }
388
Ari Saha89831742015-06-26 10:31:48 -0700389 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700390 * Gets the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700391 *
Ari Saha89831742015-06-26 10:31:48 -0700392 * @return The requestAuthenticator.
393 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700394 protected byte[] requestAuthenticator() {
Ari Saha89831742015-06-26 10:31:48 -0700395 return this.requestAuthenticator;
396 }
397
398 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700399 * Sets the authenticator.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700400 *
Ari Saha89831742015-06-26 10:31:48 -0700401 * @param authenticator The username sent to the RADIUS upon access request.
402 */
403 protected void setRequestAuthenticator(byte[] authenticator) {
404 this.requestAuthenticator = authenticator;
405 }
406
Ari Saha89831742015-06-26 10:31:48 -0700407 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700408 * Gets the username.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700409 *
Ari Saha89831742015-06-26 10:31:48 -0700410 * @return The username.
411 */
Carmelo Cascone58b53292019-09-30 12:35:31 -0700412 public byte[] username() {
Ari Saha89831742015-06-26 10:31:48 -0700413 return this.username;
414 }
415
416 /**
417 * Return the identifier of the state machine.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700418 *
Ari Saha89831742015-06-26 10:31:48 -0700419 * @return The state machine identifier.
420 */
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100421 public synchronized byte identifier() {
422 identifier = (identifier + 1) % 255;
423 identifierMap.put(identifier, this);
424 return (byte) identifier;
Ari Saha89831742015-06-26 10:31:48 -0700425 }
426
Ari Saha89831742015-06-26 10:31:48 -0700427 /**
428 * Move to the next state.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700429 *
Ray Milkey78e95a42015-09-24 08:36:45 -0700430 * @param msg message
Ari Saha89831742015-06-26 10:31:48 -0700431 */
Thomas Vachuskae9894202015-07-30 11:59:07 -0700432 private void next(int msg) {
Ari Saha89831742015-06-26 10:31:48 -0700433 currentState = transition[currentState][msg];
434 log.info("Current State " + currentState);
435 }
436
437 /**
438 * Client has requested the start action to allow network access.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700439 *
440 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700441 */
442 public void start() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700443 states[currentState].start();
Jonathan Hart5db44532018-07-12 18:13:54 -0700444
Shubham Sharma1e43c562019-06-19 14:18:12 +0000445 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.STARTED, supplicantConnectpoint));
Jonathan Hart5db44532018-07-12 18:13:54 -0700446
Shubham Sharma1e43c562019-06-19 14:18:12 +0000447 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700448 next(TRANSITION_START);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100449 identifier = this.identifier();
Ari Saha89831742015-06-26 10:31:48 -0700450 }
451
452 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000453 * An Identification information has been sent by the supplicant. Move to the
454 * next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700455 *
456 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700457 */
458 public void requestAccess() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700459 states[currentState].requestAccess();
Jonathan Hart5db44532018-07-12 18:13:54 -0700460
Shubham Sharma1e43c562019-06-19 14:18:12 +0000461 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.REQUESTED, supplicantConnectpoint));
Jonathan Hart5db44532018-07-12 18:13:54 -0700462
Shubham Sharma1e43c562019-06-19 14:18:12 +0000463 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700464 next(TRANSITION_REQUEST_ACCESS);
Ari Saha89831742015-06-26 10:31:48 -0700465 }
466
467 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000468 * RADIUS has accepted the identification. Move to the next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700469 *
470 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700471 */
472 public void authorizeAccess() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700473 states[currentState].radiusAccepted();
Shubham Sharma1e43c562019-06-19 14:18:12 +0000474 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700475 next(TRANSITION_AUTHORIZE_ACCESS);
Ari Saha89831742015-06-26 10:31:48 -0700476
Shubham Sharma1e43c562019-06-19 14:18:12 +0000477 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.APPROVED, supplicantConnectpoint));
Ari Saha89831742015-06-26 10:31:48 -0700478
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100479 // Clear mapping
480 deleteStateMachineMapping(this);
Ari Saha89831742015-06-26 10:31:48 -0700481 }
482
483 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000484 * RADIUS has denied the identification. Move to the next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700485 *
486 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700487 */
488 public void denyAccess() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700489 states[currentState].radiusDenied();
Shubham Sharma1e43c562019-06-19 14:18:12 +0000490 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700491 next(TRANSITION_DENY_ACCESS);
Jonathan Hart5db44532018-07-12 18:13:54 -0700492
Shubham Sharma1e43c562019-06-19 14:18:12 +0000493 delegate.notify(new AuthenticationEvent(AuthenticationEvent.Type.DENIED, supplicantConnectpoint));
Jonathan Hart5db44532018-07-12 18:13:54 -0700494
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100495 // Clear mappings
496 deleteStateMachineMapping(this);
Ari Saha89831742015-06-26 10:31:48 -0700497 }
498
499 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000500 * Logoff request has been requested. Move to the next state if possible.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700501 *
502 * @throws StateMachineException if authentication protocol is violated
Ari Saha89831742015-06-26 10:31:48 -0700503 */
504 public void logoff() throws StateMachineException {
Ray Milkey78e95a42015-09-24 08:36:45 -0700505 states[currentState].logoff();
Shubham Sharma1e43c562019-06-19 14:18:12 +0000506 // move to the next state
Ray Milkey78e95a42015-09-24 08:36:45 -0700507 next(TRANSITION_LOGOFF);
Ari Saha89831742015-06-26 10:31:48 -0700508 }
509
510 /**
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700511 * Gets the current state.
Thomas Vachuskae9894202015-07-30 11:59:07 -0700512 *
Shubham Sharma1e43c562019-06-19 14:18:12 +0000513 * @return The current state. Could be STATE_IDLE, STATE_STARTED, STATE_PENDING,
514 * STATE_AUTHORIZED, STATE_UNAUTHORIZED.
Ari Saha89831742015-06-26 10:31:48 -0700515 */
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700516 public int state() {
Ari Saha89831742015-06-26 10:31:48 -0700517 return currentState;
518 }
519
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700520 @Override
Ari Saha89831742015-06-26 10:31:48 -0700521 public String toString() {
Shubham Sharma1e43c562019-06-19 14:18:12 +0000522 return ("sessionId: " + this.sessionId) + "\t" + ("identifier: " + this.identifier) + "\t"
523 + ("state: " + this.currentState);
Ari Saha89831742015-06-26 10:31:48 -0700524 }
Ari Saha89831742015-06-26 10:31:48 -0700525
Ray Milkey78e95a42015-09-24 08:36:45 -0700526 abstract class State {
527 private final Logger log = getLogger(getClass());
Thomas Vachuskae9894202015-07-30 11:59:07 -0700528
Ray Milkey78e95a42015-09-24 08:36:45 -0700529 private String name = "State";
Ari Saha89831742015-06-26 10:31:48 -0700530
Ray Milkey78e95a42015-09-24 08:36:45 -0700531 public void start() throws StateMachineInvalidTransitionException {
532 log.warn("START transition from this state is not allowed.");
533 }
Ari Saha89831742015-06-26 10:31:48 -0700534
Ray Milkey78e95a42015-09-24 08:36:45 -0700535 public void requestAccess() throws StateMachineInvalidTransitionException {
536 log.warn("REQUEST ACCESS transition from this state is not allowed.");
537 }
538
539 public void radiusAccepted() throws StateMachineInvalidTransitionException {
540 log.warn("AUTHORIZE ACCESS transition from this state is not allowed.");
541 }
542
543 public void radiusDenied() throws StateMachineInvalidTransitionException {
544 log.warn("DENY ACCESS transition from this state is not allowed.");
545 }
546
547 public void logoff() throws StateMachineInvalidTransitionException {
548 log.warn("LOGOFF transition from this state is not allowed.");
549 }
Ari Saha89831742015-06-26 10:31:48 -0700550 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700551
Ray Milkey78e95a42015-09-24 08:36:45 -0700552 /**
553 * Idle state: supplicant is logged of from the network.
554 */
555 class Idle extends State {
556 private final Logger log = getLogger(getClass());
557 private String name = "IDLE_STATE";
558
Shubham Sharma1e43c562019-06-19 14:18:12 +0000559 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700560 public void start() {
561 log.info("Moving from IDLE state to STARTED state.");
562 }
Ari Saha89831742015-06-26 10:31:48 -0700563 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700564
Ray Milkey78e95a42015-09-24 08:36:45 -0700565 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000566 * Started state: supplicant has entered the network and informed the
567 * authenticator.
Ray Milkey78e95a42015-09-24 08:36:45 -0700568 */
569 class Started extends State {
570 private final Logger log = getLogger(getClass());
571 private String name = "STARTED_STATE";
572
Shubham Sharma1e43c562019-06-19 14:18:12 +0000573 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700574 public void requestAccess() {
575 log.info("Moving from STARTED state to PENDING state.");
576 }
Ari Saha89831742015-06-26 10:31:48 -0700577 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700578
Ray Milkey78e95a42015-09-24 08:36:45 -0700579 /**
Shubham Sharma1e43c562019-06-19 14:18:12 +0000580 * Pending state: supplicant has been identified by the authenticator but has
581 * not access yet.
Ray Milkey78e95a42015-09-24 08:36:45 -0700582 */
583 class Pending extends State {
584 private final Logger log = getLogger(getClass());
585 private String name = "PENDING_STATE";
586
Shubham Sharma1e43c562019-06-19 14:18:12 +0000587 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700588 public void radiusAccepted() {
589 log.info("Moving from PENDING state to AUTHORIZED state.");
590 }
591
Shubham Sharma1e43c562019-06-19 14:18:12 +0000592 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700593 public void radiusDenied() {
594 log.info("Moving from PENDING state to UNAUTHORIZED state.");
595 }
Ari Saha89831742015-06-26 10:31:48 -0700596 }
Thomas Vachuskae9894202015-07-30 11:59:07 -0700597
Ray Milkey78e95a42015-09-24 08:36:45 -0700598 /**
599 * Authorized state: supplicant port has been accepted, access is granted.
600 */
601 class Authorized extends State {
602 private final Logger log = getLogger(getClass());
603 private String name = "AUTHORIZED_STATE";
Ari Saha89831742015-06-26 10:31:48 -0700604
Shubham Sharma1e43c562019-06-19 14:18:12 +0000605 @Override
Qianqian Hu0c349812016-02-15 17:25:22 +0800606 public void start() {
607 log.info("Moving from AUTHORIZED state to STARTED state.");
608 }
609
Shubham Sharma1e43c562019-06-19 14:18:12 +0000610 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700611 public void logoff() {
Ari Saha89831742015-06-26 10:31:48 -0700612
Ray Milkey78e95a42015-09-24 08:36:45 -0700613 log.info("Moving from AUTHORIZED state to IDLE state.");
614 }
Ari Saha89831742015-06-26 10:31:48 -0700615 }
616
Ray Milkey78e95a42015-09-24 08:36:45 -0700617 /**
618 * Unauthorized state: supplicant port has been rejected, access is denied.
619 */
620 class Unauthorized extends State {
621 private final Logger log = getLogger(getClass());
622 private String name = "UNAUTHORIZED_STATE";
623
Shubham Sharma1e43c562019-06-19 14:18:12 +0000624 @Override
ke han04e47f32016-10-28 14:15:43 +0800625 public void start() {
626 log.info("Moving from UNAUTHORIZED state to STARTED state.");
627 }
628
Shubham Sharma1e43c562019-06-19 14:18:12 +0000629 @Override
Ray Milkey78e95a42015-09-24 08:36:45 -0700630 public void logoff() {
631 log.info("Moving from UNAUTHORIZED state to IDLE state.");
632 }
Ari Saha89831742015-06-26 10:31:48 -0700633 }
Ari Saha89831742015-06-26 10:31:48 -0700634
Shubham Sharma1e43c562019-06-19 14:18:12 +0000635 /**
636 * Class for cleaning the StateMachine for those session for which no response
637 * is coming--implementing timeout.
638 */
639 class CleanupTimerTask implements Runnable {
640 private final Logger log = getLogger(getClass());
641 private String sessionId;
642 private AaaManager aaaManager;
643
644 CleanupTimerTask(String sessionId, AaaManager aaaManager) {
645 this.sessionId = sessionId;
646 this.aaaManager = aaaManager;
647 }
648
649 @Override
650 public void run() {
651 StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
652 if (null != stateMachine) {
653 // Asserting if last packet received for this stateMachine session was beyond half of timeout period.
654 // StateMachine is considered eligible for cleanup when no packets has been exchanged by it with AAA
655 // Server or RG during a long period (half of timeout period). For example, when cleanup timer has
656 // been configured as 10 minutes, StateMachine would be cleaned up at the end of 10 minutes if
657 // the authentication is still pending and no packet was exchanged for this session during last 5
658 // minutes.
659
660 boolean noTrafficWithinThreshold = (System.currentTimeMillis()
661 - stateMachine.getLastPacketReceivedTime()) > ((cleanupTimerTimeOutInMins * 60 * 1000) / 2);
662
663 if ((TIMEOUT_ELIGIBLE_STATES.contains(stateMachine.state())) && noTrafficWithinThreshold) {
664 log.info("Deleting StateMachineMapping for sessionId: {}", sessionId);
665 cleanupTimer = null;
666 if (stateMachine.state() == STATE_PENDING && stateMachine.isWaitingForRadiusResponse()) {
667 aaaManager.aaaStatisticsManager.getAaaStats().increaseTimedOutPackets();
668 }
669 deleteStateMachineId(sessionId);
670 deleteStateMachineMapping(stateMachine);
671
672 // If StateMachine is not eligible for cleanup yet, reschedule cleanupTimer further.
673 } else {
674 aaaManager.scheduleStateMachineCleanupTimer(sessionId, stateMachine);
675 }
676 } else {
677 // This statement should not be logged; cleanupTimer should be cancelled for stateMachine
678 // instances which have been authenticated successfully.
679 log.warn("state-machine not found for sessionId: {}", sessionId);
680 }
681
682 }
683 }
Ari Saha89831742015-06-26 10:31:48 -0700684
Ari Saha89831742015-06-26 10:31:48 -0700685}