Skip to main content

Pythonic wrapper for the RSA sdauto32.dll soft token service

Project description

pysdtoken

A pythonic (?) ctypes wrapper for RSA SecurID Tokens I am somewhat new to Python and barely intermediate in C-style languages, so this was my attempt to fill a gap that I saw. I could not find a way to access the Soft Token using python, but lots of VPN vendors use the vendor SDK to do what I wanted to do.

Usage

You'll need a handle to the SDProcess first. This is the token service that sduato32.dll access for everything. Behind the scenes, all token requests are calling the sd process with a token serial as the argument.

from pysdtoken import SDProcess
sd = SDProcess()

Optionally set the logger level

sd = SDProcess(log_level='DEBUG')

Be forewarned: DEBUG level is going to flood you with information. This was mainly to compensate for my lack of skill/knowledge. Sorry. :grinning:

SDProcess can also take a dll path using the dll named param. It will be loaded with the ctypes windll or cdll call, so if a path is given, it try loading from the given absolute path. If a dll file is given, it will try using the current dll search path.

get the default token as a Token object

The sd process assigns a token as the "default token". I think the "default token" concept was used for the deprecated calls that did not require a serial number as an argument. As far as I can tell, the GUI version of the soft token considers the selected token to be the default. I'm not sure why you would need this in the python library. If you have one token, this function will return your token object.

my_token = sd.get_default_token()

If you have multiple tokens, just check the list of tokens in the SDProcess object:

sd.tokens
[Token(000123456789, PINless), Token(000111122311, PINless)*, Token(000234567654, PINless), Token(12343212345, PINless)]

The default token is marked with a *. If you want a different token, just grab it from the list:

my_token2 = sd.tokens[0]
>>> my_token2
Token(000123456789, PINless)

You can also get a token by its serial number. I don't have a use case for this, but...I dunno.

specific_token = sd.get_token_by_serial('1234567890')

The SD Process also holds the last token error that occurred.

>>> sd.get_token_error()
'Last Token Error from SDProcess: 17: ERROR_BUFFER_TOO_SMALL_ERROR'

It was useful while coding this library, but has limited use in any implementation I can think of.

Close the process

You should close the process because the SDK says you should close the process. I'm sure python will clean up the pointer/handle, but I don't know if the process itself lingers.

sd.close_service()

If you close the service, the token objects will cease working:

>>> tkn = sd.get_default_token()
>>> sd.close_service()
>>> tkn.get_current_code()
ERROR:pysdtoken.pysdtoken:Error getting token code.
TokenInfo(passcode='', tokencode='', time_left=0)

If you do this accidentally, you can always create a new handle and set the sd process on the existing token object:

>>> sd2 = SDProcess()
>>> tkn.set_sd_process(sd2)
>>> tkn.get_current_code()
TokenInfo(passcode='68545942', tokencode='68545942', time_left=9)

Token

get_current_code()

The function returns a named tuple of the passcode, tokencode, and time left. For pinless tokens:

  • if you don't send a PIN, passcode and tokencode are identical
  • if you send a PIN, passcode will be the tokencode with the pin prepended
>>>> my_token.get_current_code()
TokenInfo(passcode='80851855', tokencode='80851855', time_left=6)`

For tokens that require a pin before getting the code

my_token.get_current_code(pin)
mytoken.get_current_code('1234')
TokenInfo(passcode='123450484340', tokencode='50484340', time_left=7)

Get individual values from the token:

>>> mytoken.get_current_code('1234').passcode
'123440269669'
>>> mytoken.get_current_code('1234').tokencode
'40269669'
>>> mytoken.get_current_code('1234').time_left
23

You can also get the expiration date of the token

>>> tkn.get_expiration_date()
datetime.date(2035, 12, 31)
>>> print(tkn.get_expiration_date())
2035-12-31
>>>

Get a code from each using pin '1234'. I don't know why you would do this, but you can.

>>> for token in sd.tokens:
...     token.get_current_code('1234').passcode
...
'66268520'
'123454816010'
'89718449'
'62015065'
>>>

get_next_code()

Get the next code from the token. This is useful when you're in next token mode or testing your token. I've also implemented the backend "can_token_get_next_code()" method, but I have no idea why it's needed. I've never seen it return anything but True.

>>> tkn.get_next_code()
TokenInfo(passcode='84226585', tokencode='84226585', time_left=7)
>>> tkn.can_get_next_code()
True

Set the pin style

You can set the pin style for the token. It defaults to PINless because the info is not available from the sdauto process.

>>> sd.valid_pin_styles
('PINless', 'PINPad-style', 'Fob-style')
>>> tkn.set_pin_style('PINPad-style')
>>> tkn.pin_style
'PINPad-style'
>>>

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pysdtoken-1.0.1.tar.gz (14.2 kB view hashes)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page