Class: RSA::SecurID::Session
- Inherits:
-
Object
- Object
- RSA::SecurID::Session
- Defined in:
- lib/securid.rb,
ext/securid/securid.c
Overview
Manages a single authentication session against the RSA ACE server. Handles the various life cycle events that may occur, such as token resynchronization and pin changes. Includes a test mode that can simulate various responses when an ACE server is not present (for example during local development). Instances of this class should not be reused unless the RSA flow (and this documentation) indicates otherwise (for example, you can issue an #authenticate call after a successful #change_pin call).
This class assumes you have an understanding of the RSA authentication flow. Timeouts on state transitions are enforced by the server, and are not documented here as they may change between ACE releases.
In test mode, this class will send no network traffic and not talk to the RSA agent. The RSA SDK libraries do not even need to be present, just the header files. In the normal mode, the server configuration is imported by the agent directly.
Constant Summary collapse
- AUTHENTICATED =
:authenticated
- DENIED =
:denied
- MUST_CHANGE_PIN =
:must_change_pin
- MUST_RESYNCHRONIZE =
:must_resynchronize
- UNSTARTED =
nil
Instance Attribute Summary collapse
-
#status ⇒ Object
readonly
Returns the current state of the session, which is one of AUTHENTICATED, DENIED, MUST_CHANGE_PIN, MUST_RESYNCHRONIZE, or UNSTARTED.
Instance Method Summary collapse
-
#authenticate(username, passcode) ⇒ Symbol
Attempts to authenticate the user against the RSA ACE server using the username, pin, and token value.
-
#authenticated? ⇒ Boolean
Checks if the session is in the AUTHENTICATED state.
-
#cancel_pin ⇒ true
Cancels a pin change request.
-
#change_pin(pin) ⇒ true
Changes the pin associated with the token.
-
#change_pin? ⇒ Boolean
Checks if the session is in the MUST_CHANGE_PIN state.
-
#denied? ⇒ Boolean
Checks if the session is in the DENIED state.
-
#initialize(options = {}) ⇒ Object
constructor
Creates a new session.
-
#resynchronize(passcode) ⇒ Symbol
Completes the token resynchronize flow.
-
#resynchronize? ⇒ Boolean
Checks if the session is in the MUST_RESYNCHRONIZE state.
Constructor Details
#initialize(options = {}) ⇒ Object
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
# File 'ext/securid/securid.c', line 308
static VALUE securid_session_initialize(int argc, VALUE *argv, VALUE self)
{
securid_session_t *session;
VALUE session_data;
VALUE options = Qnil;
VALUE test_mode = Qfalse;
rb_scan_args(argc, argv, "0:", &options);
// Allocate a new securid_session_t and wrap it as a ruby object
session_data = TypedData_Make_Struct(rb_cData, securid_session_t, &securid_session_data_type, session);
session->handle = SDI_HANDLE_NONE;
// Stick our new securid_session_t into an instance variable on self
rb_ivar_set(self, securid_id_session, session_data);
// Initalize our status to nil
rb_ivar_set(self, securid_id_session_status, Qnil);
// Initalize our test_mode to the supplied option
if (!NIL_P(options))
{
test_mode = rb_hash_aref(options, rb_symTestMode);
}
rb_ivar_set(self, securid_id_session_test_mode, test_mode);
return self;
}
|
Instance Attribute Details
#status ⇒ Object (readonly)
Returns the current state of the session, which is one of AUTHENTICATED, DENIED, MUST_CHANGE_PIN, MUST_RESYNCHRONIZE, or UNSTARTED.
23 24 25 |
# File 'lib/securid.rb', line 23 def status @status end |
Instance Method Details
#authenticate(username, passcode) ⇒ Symbol
Attempts to authenticate the user against the RSA ACE server using the username, pin, and token value. It will indicate if authentication fails due to token issue (pin change or resynchronization request), or a normal authentication failure (denied). The session object will have the returned status stored in its status attribute. A session with a status of AUTHENTICATED or DENIED can not be reused. A session with a status of MUST_CHANGE_PIN or MUST_RESYNCHRONIZE can be used to complete the required step, and then be used to reauthenticate with another call to #authenticate
This method can only be called when the session state is UNSTARTED. Calling it in any other state will result in a RSA::SecurID::SecurIDError being raised.
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 |
# File 'ext/securid/securid.c', line 358
static VALUE securid_session_authenticate(VALUE self, VALUE username, VALUE passcode)
{
int return_value;
VALUE session_data;
VALUE status = Qnil;
securid_session_t *session;
SD_CHAR *username_str;
SD_CHAR *passcode_str;
// Check that we are in an allowed state
securid_session_check_status(self, (ID)0);
if (!securid_session_is_test_mode(self))
{
// Fetch our securid_session_t from self
session_data = rb_ivar_get(self, securid_id_session);
TypedData_Get_Struct(session_data, securid_session_t, &securid_session_data_type, session);
// Convert our arguments to C Strings
username_str = StringValueCStr(username);
passcode_str = StringValueCStr(passcode);
// Initalize the session handler
return_value = SD_Init(&session->handle);
if (return_value != ACM_OK)
{
rb_raise(rb_eSecurIDError, "Failed to initialize session handler - code %d", return_value);
}
// Lock the username, part of the Two Step Authentication flow
return_value = SD_Lock(session->handle, username_str);
if (return_value != ACM_OK)
{
rb_raise(rb_eSecurIDError, "Failed to lock username - code %d", return_value);
}
return_value = SD_Check(session->handle, passcode_str, username_str);
if (return_value == ACM_OK)
{
// We are authenticated
status = rb_const_get(rb_cRSASecurIDSession, securid_id_session_authenticated);
} else if (return_value == ACM_ACCESS_DENIED)
{
// We are denied
status = rb_const_get(rb_cRSASecurIDSession, securid_id_session_denied);
} else if (return_value == ACM_NEXT_CODE_REQUIRED)
{
// We need the user to resynchronize the token
status = rb_const_get(rb_cRSASecurIDSession, securid_id_session_resynchronize);
} else if (return_value == ACM_NEW_PIN_REQUIRED)
{
// We need the user to enter a new pin
status = rb_const_get(rb_cRSASecurIDSession, securid_id_session_change_pin);
} else
{
// Internal error of some sort
rb_raise(rb_eSecurIDError, "Failed to authenticate the user - code %d", return_value);
}
} else
{
if (securid_session_is_test_mode_resynchronize(self))
{
// Force resynchronize in resynchronization test mode
status = rb_const_get(rb_cRSASecurIDSession, securid_id_session_resynchronize);
} else if (securid_session_is_test_mode_change_pin(self))
{
// Force pin change in pin change test mode
status = rb_const_get(rb_cRSASecurIDSession, securid_id_session_change_pin);
} else if (securid_session_is_test_mode_denied(self))
{
// Force denied in denied test mode
status = rb_const_get(rb_cRSASecurIDSession, securid_id_session_denied);
} else
{
// Force success in test mode
status = rb_const_get(rb_cRSASecurIDSession, securid_id_session_authenticated);
}
}
// Update our status
rb_ivar_set(self, securid_id_session_status, status);
return status;
}
|
#authenticated? ⇒ Boolean
Checks if the session is in the AUTHENTICATED state.
45 46 47 |
# File 'lib/securid.rb', line 45 def authenticated? @status == AUTHENTICATED end |
#cancel_pin ⇒ true
Cancels a pin change request. On success the session state will be set back to UNSTARTED. This method can only be called when the session is in the MUST_CHANGE_PIN state. Calling it in any other state will raise a RSA::SecurID::SecurIDError.
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 |
# File 'ext/securid/securid.c', line 513
static VALUE securid_session_cancel_pin(VALUE self)
{
VALUE session_data;
securid_session_t *session;
SD_CHAR *pin_str;
int return_value;
// Check that we are in an allowed state
securid_session_check_status(self, securid_id_session_change_pin);
if (!securid_session_is_test_mode(self))
{
// Fetch our securid_session_t from self
session_data = rb_ivar_get(self, securid_id_session);
TypedData_Get_Struct(session_data, securid_session_t, &securid_session_data_type, session);
return_value = SD_Pin(session->handle, NULL);
if (return_value != ACM_NEW_PIN_ACCEPTED)
{
rb_raise(rb_eSecurIDError, "Failed to cancel changing the pin - code %d", return_value);
}
}
// Update our status to be unstarted.
rb_ivar_set(self, securid_id_session_status, Qnil);
return Qtrue;
}
|
#change_pin(pin) ⇒ true
Changes the pin associated with the token. This method can only be called when the session is in the MUST_CHANGE_PIN state. Calling it in any other state will result in a RSA::SecurID::SecurIDError being raised. After calling #change_pin, the session state is reset to UNSTARTED. A subsequent call to #authenticate is needed to actually authenticate the user.
The typical flow for chaning the pin is first call #authenticate with the old pin, see that we are in the MUST_CHANGE_PIN state, call #change_pin to with the new pin, then call #authenticate with the new pin to finally authorize the user.
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 |
# File 'ext/securid/securid.c', line 463
static VALUE securid_session_change_pin(VALUE self, VALUE pin)
{
VALUE session_data;
securid_session_t *session;
SD_CHAR *pin_str;
int return_value;
// Check that we are in an allowed state
securid_session_check_status(self, securid_id_session_change_pin);
if (!securid_session_is_test_mode(self))
{
// Fetch our securid_session_t from self
session_data = rb_ivar_get(self, securid_id_session);
TypedData_Get_Struct(session_data, securid_session_t, &securid_session_data_type, session);
// Convert our arguments to C Strings
pin_str = StringValueCStr(pin);
return_value = SD_Pin(session->handle, pin_str);
if (return_value != ACM_NEW_PIN_ACCEPTED)
{
// Changing pin failed for internal reasons
rb_raise(rb_eSecurIDError, "Failed to change the pin - code %d", return_value);
}
} else
{
if (securid_session_is_test_mode_change_pin(self))
{
// exit pin change test mode for regular test mode
rb_ivar_set(self, securid_id_session_test_mode, Qtrue);
}
}
// Update our status to be unstarted.
rb_ivar_set(self, securid_id_session_status, Qnil);
return Qtrue;
}
|
#change_pin? ⇒ Boolean
Checks if the session is in the MUST_CHANGE_PIN state.
39 40 41 |
# File 'lib/securid.rb', line 39 def change_pin? @status == MUST_CHANGE_PIN end |
#denied? ⇒ Boolean
Checks if the session is in the DENIED state.
51 52 53 |
# File 'lib/securid.rb', line 51 def denied? @status == DENIED end |
#resynchronize(passcode) ⇒ Symbol
Completes the token resynchronize flow. This method should be called when the server is requesting the user to resynchronize their token. It is not possible to initiate a resychronization request with this method. The session must be in the MUST_RESYNCHRONIZE state. Callig it in any other state will raise a RSA::SecurID::SecurIDError.
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 |
# File 'ext/securid/securid.c', line 555
static VALUE securid_session_resynchronize(VALUE self, VALUE passcode)
{
int return_value;
VALUE session_data;
VALUE status;
securid_session_t *session;
SD_CHAR *passcode_str;
// Check that we are in an allowed state
securid_session_check_status(self, securid_id_session_resynchronize);
if (!securid_session_is_test_mode(self))
{
// Fetch our securid_session_t from self
session_data = rb_ivar_get(self, securid_id_session);
TypedData_Get_Struct(session_data, securid_session_t, &securid_session_data_type, session);
// Convert our arguments to C Strings
passcode_str = StringValueCStr(passcode);
// Initalize the session handler
return_value = SD_Next(session->handle, passcode_str);
if (return_value == ACM_OK)
{
// We are authenticated
status = rb_const_get(rb_cRSASecurIDSession, securid_id_session_authenticated);
} else if (return_value == ACM_ACCESS_DENIED)
{
// We are denied
status = rb_const_get(rb_cRSASecurIDSession, securid_id_session_denied);
} else {
// Internal error of some sort
rb_raise(rb_eSecurIDError, "Failed to synchronize the token - code %d", return_value);
}
} else {
if (securid_session_is_test_mode_resynchronize(self))
{
// exit resynchronization test mode for regular test mode
rb_ivar_set(self, securid_id_session_test_mode, Qtrue);
}
// Force success in test mode
status = rb_const_get(rb_cRSASecurIDSession, securid_id_session_authenticated);
}
// Update our status
rb_ivar_set(self, securid_id_session_status, status);
return status;
}
|
#resynchronize? ⇒ Boolean
Checks if the session is in the MUST_RESYNCHRONIZE state.
33 34 35 |
# File 'lib/securid.rb', line 33 def resynchronize? @status == MUST_RESYNCHRONIZE end |