securid 0.1 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/ext/securid/extconf.rb +2 -1
- data/ext/securid/securid.c +836 -124
- data/ext/securid/securid.h +11 -0
- data/lib/securid.rb +56 -0
- metadata +30 -45
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 3ba152af81ffc60b57fdebc419824bb5b98cf74e
|
|
4
|
+
data.tar.gz: 6c6527fa4fe5f43bebc9adf130b7394ff8c3c852
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 5d8d893afbe8ad4feb725d791d5d5b7ca072d45ab5e42c110908c21f20e1bc26abcae58d3e7afa01659c96ec72a86bc5ac1a1163887eaec287b3e080d7b908b3
|
|
7
|
+
data.tar.gz: 1a56068c8874462c4b78678e45eb2e27afe150b55c5403d14bb395acc12d8c31160ca704fb6046d3b349bb0b406603681f598839e9ffa3bc58b6be716c9f0f38
|
data/ext/securid/extconf.rb
CHANGED
data/ext/securid/securid.c
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
#include "ruby.h"
|
|
2
2
|
#include "acexport.h"
|
|
3
|
+
#include "status_display.h"
|
|
4
|
+
#include "securid.h"
|
|
5
|
+
|
|
6
|
+
#ifdef WIN32
|
|
7
|
+
#include <winsock.h>
|
|
8
|
+
#else
|
|
9
|
+
#include <sys/socket.h>
|
|
10
|
+
#include <netinet/in.h>
|
|
11
|
+
#include <arpa/inet.h>
|
|
12
|
+
#endif
|
|
13
|
+
|
|
14
|
+
#define CTEST(v) ((v) ? Qtrue : Qfalse)
|
|
3
15
|
|
|
4
16
|
// module RSA
|
|
5
17
|
static VALUE rb_mRSA;
|
|
@@ -10,133 +22,833 @@ static VALUE rb_mRSASecurID;
|
|
|
10
22
|
// class RSA::SecurID::SecurIDError < StandardError
|
|
11
23
|
static VALUE rb_eSecurIDError;
|
|
12
24
|
|
|
13
|
-
//
|
|
14
|
-
static VALUE
|
|
25
|
+
// class RSA::SecurID::Session
|
|
26
|
+
static VALUE rb_cRSASecurIDSession;
|
|
27
|
+
|
|
28
|
+
// ID used for session storage on RSA::SecurID::Session
|
|
29
|
+
ID securid_id_session;
|
|
30
|
+
|
|
31
|
+
// ID used for status storage on RSA::SecurID::Session
|
|
32
|
+
ID securid_id_session_status;
|
|
33
|
+
|
|
34
|
+
// ID used for test mode storage on RSA::SecurID::Session
|
|
35
|
+
ID securid_id_session_test_mode;
|
|
36
|
+
|
|
37
|
+
// symbol version of 'test_mode'
|
|
38
|
+
static VALUE rb_symTestMode;
|
|
39
|
+
|
|
40
|
+
// symbol version of 'resynchronize'
|
|
41
|
+
static VALUE rb_symResynchronize;
|
|
42
|
+
|
|
43
|
+
// symbol version of 'change_pin'
|
|
44
|
+
static VALUE rb_symChangePin;
|
|
45
|
+
|
|
46
|
+
// symbol version of 'denied'
|
|
47
|
+
static VALUE rb_symDenied;
|
|
48
|
+
|
|
49
|
+
// IDs used to identify RSA::SecurID::Session constants
|
|
50
|
+
ID securid_id_session_authenticated;
|
|
51
|
+
ID securid_id_session_denied;
|
|
52
|
+
ID securid_id_session_change_pin;
|
|
53
|
+
ID securid_id_session_resynchronize;
|
|
54
|
+
|
|
55
|
+
// symbols used to in the agent status hash
|
|
56
|
+
static VALUE rb_symConfigVersion; // 'config_version'
|
|
57
|
+
static VALUE rb_symMaxServers; // 'max_servers'
|
|
58
|
+
static VALUE rb_symMaxReplicas; // 'max_replicas'
|
|
59
|
+
static VALUE rb_symMaxRetries; // 'max_retries'
|
|
60
|
+
static VALUE rb_symBaseTimeout; // 'base_timeout'
|
|
61
|
+
static VALUE rb_symUseDES; // 'use_des'
|
|
62
|
+
static VALUE rb_symTrusted; // 'trusted'
|
|
63
|
+
static VALUE rb_symPort; // 'port'
|
|
64
|
+
static VALUE rb_symServiceName; // 'service_name'
|
|
65
|
+
static VALUE rb_symServiceProtocol; // 'service_protocol'
|
|
66
|
+
static VALUE rb_symServiceProtocolVersion; // 'service_protocol_version'
|
|
67
|
+
static VALUE rb_symServerReleaseNumber; // 'server_release_number'
|
|
68
|
+
static VALUE rb_symServers; // 'servers'
|
|
69
|
+
static VALUE rb_symMajor; // 'major'
|
|
70
|
+
static VALUE rb_symMinor; // 'minor'
|
|
71
|
+
static VALUE rb_symPatch; // 'patch'
|
|
72
|
+
static VALUE rb_symBuild; // 'build'
|
|
73
|
+
static VALUE rb_symAddress; // 'address'
|
|
74
|
+
static VALUE rb_symActiveAddress; // 'active_address'
|
|
75
|
+
static VALUE rb_symAliases; // 'aliases'
|
|
76
|
+
static VALUE rb_symDisplayStatus; // 'display_status'
|
|
77
|
+
static VALUE rb_symHostname; // 'hostname'
|
|
78
|
+
static VALUE rb_symPrimary; // 'primary'
|
|
79
|
+
static VALUE rb_symMaster; // 'master'
|
|
80
|
+
static VALUE rb_symSlave; // 'slave'
|
|
81
|
+
static VALUE rb_symSelectable; // 'selectable'
|
|
82
|
+
static VALUE rb_symEmergency; // 'emergency'
|
|
83
|
+
static VALUE rb_symSuspended; // 'suspended'
|
|
84
|
+
static VALUE rb_symAddressVerified; // 'address_verified'
|
|
85
|
+
|
|
86
|
+
static void securid_session_free(void *ptr)
|
|
15
87
|
{
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
// a hint to the developer about how long to display the next
|
|
27
|
-
// prompt string for the user
|
|
28
|
-
SD_I32 respTimeout;
|
|
29
|
-
|
|
30
|
-
// an indicator of the maximum number of bytes of data expected
|
|
31
|
-
// in the next developer-supplied response
|
|
32
|
-
SD_I32 nextRespLen;
|
|
33
|
-
|
|
34
|
-
// a developer-supplied character array to be filled in by the
|
|
35
|
-
// API with the string that the caller uses as the next message
|
|
36
|
-
// displayed to the user
|
|
37
|
-
SD_CHAR promptStr[512];
|
|
38
|
-
|
|
39
|
-
// the size of the developer-supplied storage for the prompt
|
|
40
|
-
// string
|
|
41
|
-
SD_I32 promptStrLen;
|
|
42
|
-
|
|
43
|
-
// a flag that is set by the API to indicate whether more data
|
|
44
|
-
// is needed by the authentication context
|
|
45
|
-
SD_BOOL moreData;
|
|
46
|
-
|
|
47
|
-
// a flag that guides the developer as to whether the next
|
|
48
|
-
// expected response is echoed to the screen
|
|
49
|
-
SD_BOOL echoFlag;
|
|
50
|
-
|
|
51
|
-
// the final authentication status
|
|
52
|
-
SD_I32 authStatus;
|
|
53
|
-
|
|
54
|
-
// initialize the authentication library. even though it will only do anything
|
|
55
|
-
// the first time it is called, subsequent calls should still return true if the
|
|
56
|
-
// initialization previously succeeded.
|
|
57
|
-
if (!AceInitialize())
|
|
58
|
-
{
|
|
59
|
-
// the authentication library failed to initialize.
|
|
60
|
-
rb_raise(rb_eSecurIDError, "Failed to initialize authentication library");
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
int retVal;
|
|
64
|
-
|
|
65
|
-
// reset size of prompt string
|
|
66
|
-
promptStrLen = sizeof(promptStr);
|
|
67
|
-
|
|
68
|
-
// start our authentication attempt by first sending the username to
|
|
69
|
-
// the authentication manager.
|
|
70
|
-
retVal = AceStartAuth(&aceHdl, userID, strlen(userID), &moreData, &echoFlag, &respTimeout, &nextRespLen, promptStr, &promptStrLen);
|
|
71
|
-
|
|
72
|
-
if (retVal != ACM_OK)
|
|
73
|
-
{
|
|
74
|
-
// the authentication attempt could not be started for some reason.
|
|
75
|
-
rb_raise(rb_eSecurIDError, "Failed to start authentication attempt - Code %d", retVal);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (!moreData)
|
|
79
|
-
{
|
|
80
|
-
// the authentication manager should have asked for a passcode
|
|
81
|
-
AceCloseAuth(aceHdl);
|
|
82
|
-
rb_raise(rb_eSecurIDError, "Authentication manager did not ask for a passcode");
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// reset size of prompt string
|
|
86
|
-
promptStrLen = sizeof(promptStr);
|
|
87
|
-
|
|
88
|
-
// the authentication manager wants us to prompt the user for more data. because
|
|
89
|
-
// this function is non-interactive, we assume the manager wants the passcode. since
|
|
90
|
-
// we already have it, we'll pass it along without prompting the user.
|
|
91
|
-
retVal = AceContinueAuth(aceHdl, pass, strlen(pass), &moreData, &echoFlag, &respTimeout, &nextRespLen, promptStr, &promptStrLen);
|
|
92
|
-
|
|
93
|
-
if (retVal != ACM_OK)
|
|
94
|
-
{
|
|
95
|
-
// the authentication attempt could not be continued for some reason.
|
|
96
|
-
AceCloseAuth(aceHdl);
|
|
97
|
-
rb_raise(rb_eSecurIDError, "Failed to continue authentication attempt - Code %d", retVal);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (moreData)
|
|
101
|
-
{
|
|
102
|
-
// either our assumption that the authentication manager wanted the passcode was
|
|
103
|
-
// incorrect, or something else went wrong.
|
|
104
|
-
AceCloseAuth(aceHdl);
|
|
105
|
-
rb_raise(rb_eSecurIDError, "Authentication manager asked for more than a passcode");
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// ask the authentication manager for the status of this authentication attempt.
|
|
109
|
-
retVal = AceGetAuthenticationStatus(aceHdl, &authStatus);
|
|
110
|
-
|
|
111
|
-
// finalize this authentication attempt by closing our handle.
|
|
112
|
-
AceCloseAuth(aceHdl);
|
|
113
|
-
|
|
114
|
-
if (retVal != ACE_SUCCESS)
|
|
115
|
-
{
|
|
116
|
-
// the authentication status could not be retrieved for some reason.
|
|
117
|
-
rb_raise(rb_eSecurIDError, "Failed to retrieve authentication status - Code %d", retVal);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// check the status of the authentication attempt and return true or false.
|
|
121
|
-
if (authStatus == ACM_OK)
|
|
122
|
-
return Qtrue;
|
|
123
|
-
else if (authStatus == ACM_ACCESS_DENIED)
|
|
124
|
-
return Qfalse;
|
|
125
|
-
|
|
126
|
-
rb_raise(rb_eSecurIDError, "Unexpected authentication status - Code %d", authStatus);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
void Init_securid ()
|
|
88
|
+
securid_session_t *session = (securid_session_t *)ptr;
|
|
89
|
+
if (session->handle != SDI_HANDLE_NONE)
|
|
90
|
+
{
|
|
91
|
+
SD_Close(session->handle);
|
|
92
|
+
session->handle = SDI_HANDLE_NONE;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
static void securid_session_mark(void *ptr)
|
|
130
97
|
{
|
|
131
|
-
|
|
132
|
-
|
|
98
|
+
|
|
99
|
+
}
|
|
133
100
|
|
|
134
|
-
|
|
135
|
-
|
|
101
|
+
static size_t securid_session_size(void const *ptr)
|
|
102
|
+
{
|
|
103
|
+
return sizeof(securid_session_t);
|
|
104
|
+
}
|
|
136
105
|
|
|
137
|
-
|
|
138
|
-
|
|
106
|
+
struct rb_data_type_struct securid_session_data_type = {
|
|
107
|
+
"RSA::SecurID::Session Storage",
|
|
108
|
+
{
|
|
109
|
+
securid_session_mark, /* dmark */
|
|
110
|
+
securid_session_free, /* dfree */
|
|
111
|
+
securid_session_size, /* dsize */
|
|
112
|
+
{NULL, NULL}
|
|
113
|
+
},
|
|
114
|
+
NULL,
|
|
115
|
+
NULL,
|
|
116
|
+
RUBY_TYPED_FREE_IMMEDIATELY
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
/*
|
|
120
|
+
* @overload authenticate(username, password)
|
|
121
|
+
* @deprecated Use {Session#authenticate} instead.
|
|
122
|
+
* @param username [String] The username to authenticate with.
|
|
123
|
+
* @param passcode [String] The passcode to authenticate with. Passcodes are the user's pin
|
|
124
|
+
* concatenated with the current token value.
|
|
125
|
+
*
|
|
126
|
+
* Performs a basic non-interactive authentication attempt.
|
|
127
|
+
*
|
|
128
|
+
* @return [Boolean] +true+ on authentication succes, +false+ on authentication denial.
|
|
129
|
+
* @raise [SecureIDError] if anything beyond a basic rejection of the authentication
|
|
130
|
+
* happened such as a pin must be changed, the token needs resynchronization, the ACE
|
|
131
|
+
* server can't be found, etc.
|
|
132
|
+
*/
|
|
133
|
+
static VALUE securid_authenticate(VALUE self, VALUE username, VALUE passcode)
|
|
134
|
+
{
|
|
135
|
+
// the authentication handle representing a single authentication
|
|
136
|
+
// context, i.e. a multi-step authentication attempt
|
|
137
|
+
SDI_HANDLE aceHdl;
|
|
138
|
+
|
|
139
|
+
// a string containing the username
|
|
140
|
+
SD_CHAR *userID = StringValuePtr(username);
|
|
141
|
+
|
|
142
|
+
// a string containing the passcode
|
|
143
|
+
SD_CHAR *pass = StringValuePtr(passcode);
|
|
144
|
+
|
|
145
|
+
// a hint to the developer about how long to display the next
|
|
146
|
+
// prompt string for the user
|
|
147
|
+
SD_I32 respTimeout;
|
|
148
|
+
|
|
149
|
+
// an indicator of the maximum number of bytes of data expected
|
|
150
|
+
// in the next developer-supplied response
|
|
151
|
+
SD_I32 nextRespLen;
|
|
152
|
+
|
|
153
|
+
// a developer-supplied character array to be filled in by the
|
|
154
|
+
// API with the string that the caller uses as the next message
|
|
155
|
+
// displayed to the user
|
|
156
|
+
SD_CHAR promptStr[512];
|
|
157
|
+
|
|
158
|
+
// the size of the developer-supplied storage for the prompt
|
|
159
|
+
// string
|
|
160
|
+
SD_I32 promptStrLen;
|
|
161
|
+
|
|
162
|
+
// a flag that is set by the API to indicate whether more data
|
|
163
|
+
// is needed by the authentication context
|
|
164
|
+
SD_BOOL moreData;
|
|
165
|
+
|
|
166
|
+
// a flag that guides the developer as to whether the next
|
|
167
|
+
// expected response is echoed to the screen
|
|
168
|
+
SD_BOOL echoFlag;
|
|
169
|
+
|
|
170
|
+
// the final authentication status
|
|
171
|
+
SD_I32 authStatus;
|
|
172
|
+
|
|
173
|
+
// initialize the authentication library. even though it will only do anything
|
|
174
|
+
// the first time it is called, subsequent calls should still return true if the
|
|
175
|
+
// initialization previously succeeded.
|
|
176
|
+
if (!AceInitialize())
|
|
177
|
+
{
|
|
178
|
+
// the authentication library failed to initialize.
|
|
179
|
+
rb_raise(rb_eSecurIDError, "Failed to initialize authentication library");
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
int retVal;
|
|
183
|
+
|
|
184
|
+
// reset size of prompt string
|
|
185
|
+
promptStrLen = sizeof(promptStr);
|
|
186
|
+
|
|
187
|
+
// start our authentication attempt by first sending the username to
|
|
188
|
+
// the authentication manager.
|
|
189
|
+
retVal = AceStartAuth(&aceHdl, userID, strlen(userID), &moreData, &echoFlag, &respTimeout, &nextRespLen, promptStr, &promptStrLen);
|
|
190
|
+
|
|
191
|
+
if (retVal != ACM_OK)
|
|
192
|
+
{
|
|
193
|
+
// the authentication attempt could not be started for some reason.
|
|
194
|
+
rb_raise(rb_eSecurIDError, "Failed to start authentication attempt - Code %d", retVal);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (!moreData)
|
|
198
|
+
{
|
|
199
|
+
// the authentication manager should have asked for a passcode
|
|
200
|
+
AceCloseAuth(aceHdl);
|
|
201
|
+
rb_raise(rb_eSecurIDError, "Authentication manager did not ask for a passcode");
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// reset size of prompt string
|
|
205
|
+
promptStrLen = sizeof(promptStr);
|
|
206
|
+
|
|
207
|
+
// the authentication manager wants us to prompt the user for more data. because
|
|
208
|
+
// this function is non-interactive, we assume the manager wants the passcode. since
|
|
209
|
+
// we already have it, we'll pass it along without prompting the user.
|
|
210
|
+
retVal = AceContinueAuth(aceHdl, pass, strlen(pass), &moreData, &echoFlag, &respTimeout, &nextRespLen, promptStr, &promptStrLen);
|
|
211
|
+
|
|
212
|
+
if (retVal != ACM_OK)
|
|
213
|
+
{
|
|
214
|
+
// the authentication attempt could not be continued for some reason.
|
|
215
|
+
AceCloseAuth(aceHdl);
|
|
216
|
+
rb_raise(rb_eSecurIDError, "Failed to continue authentication attempt - Code %d", retVal);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (moreData)
|
|
220
|
+
{
|
|
221
|
+
// either our assumption that the authentication manager wanted the passcode was
|
|
222
|
+
// incorrect, or something else went wrong.
|
|
223
|
+
AceCloseAuth(aceHdl);
|
|
224
|
+
rb_raise(rb_eSecurIDError, "Authentication manager asked for more than a passcode");
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// ask the authentication manager for the status of this authentication attempt.
|
|
228
|
+
retVal = AceGetAuthenticationStatus(aceHdl, &authStatus);
|
|
229
|
+
|
|
230
|
+
// finalize this authentication attempt by closing our handle.
|
|
231
|
+
AceCloseAuth(aceHdl);
|
|
232
|
+
|
|
233
|
+
if (retVal != ACE_SUCCESS)
|
|
234
|
+
{
|
|
235
|
+
// the authentication status could not be retrieved for some reason.
|
|
236
|
+
rb_raise(rb_eSecurIDError, "Failed to retrieve authentication status - Code %d", retVal);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// check the status of the authentication attempt and return true or false.
|
|
240
|
+
if (authStatus == ACM_OK)
|
|
241
|
+
return Qtrue;
|
|
242
|
+
else if (authStatus == ACM_ACCESS_DENIED)
|
|
243
|
+
return Qfalse;
|
|
244
|
+
|
|
245
|
+
rb_raise(rb_eSecurIDError, "Unexpected authentication status - Code %d", authStatus);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Checks that the status of the session `self` matches the constant identified by `status_id`. Pass
|
|
249
|
+
// 0 for `status_id` to check if the the status of `self` is Qnil.
|
|
250
|
+
void securid_session_check_status(VALUE self, ID status_id)
|
|
251
|
+
{
|
|
252
|
+
VALUE current_status = rb_ivar_get(self, securid_id_session_status);
|
|
253
|
+
VALUE compared_status;
|
|
254
|
+
int invalid_state;
|
|
255
|
+
|
|
256
|
+
if (status_id)
|
|
257
|
+
{
|
|
258
|
+
compared_status = rb_const_get(rb_cRSASecurIDSession, status_id);
|
|
259
|
+
invalid_state = !rb_eql(current_status, compared_status);
|
|
260
|
+
} else
|
|
261
|
+
{
|
|
262
|
+
invalid_state = !NIL_P(current_status);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (invalid_state)
|
|
266
|
+
{
|
|
267
|
+
rb_raise(rb_eSecurIDError, "Session is in an invalid state for the requested operation");
|
|
268
|
+
}
|
|
269
|
+
}
|
|
139
270
|
|
|
140
|
-
|
|
141
|
-
|
|
271
|
+
int securid_session_is_test_mode(VALUE self)
|
|
272
|
+
{
|
|
273
|
+
VALUE test_mode = rb_ivar_get(self, securid_id_session_test_mode);
|
|
274
|
+
return RTEST(test_mode);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
int securid_session_is_test_mode_resynchronize(VALUE self)
|
|
278
|
+
{
|
|
279
|
+
VALUE test_mode = rb_ivar_get(self, securid_id_session_test_mode);
|
|
280
|
+
return rb_eql(test_mode, rb_symResynchronize);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
int securid_session_is_test_mode_change_pin(VALUE self)
|
|
284
|
+
{
|
|
285
|
+
VALUE test_mode = rb_ivar_get(self, securid_id_session_test_mode);
|
|
286
|
+
return rb_eql(test_mode, rb_symChangePin);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
int securid_session_is_test_mode_denied(VALUE self)
|
|
290
|
+
{
|
|
291
|
+
VALUE test_mode = rb_ivar_get(self, securid_id_session_test_mode);
|
|
292
|
+
return rb_eql(test_mode, rb_symDenied);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/*
|
|
296
|
+
* @overload initialize(options={})
|
|
297
|
+
* @param options [Hash{Symbol=>Symbol,Boolean}] A hash of options.
|
|
298
|
+
* @option options [Symbol,Boolean] :test_mode (false) Indicates if the test mode
|
|
299
|
+
* should be enabled, and if so, what mode to enable.
|
|
300
|
+
* Allowed options are: +true+, +false+, +:resynchronize+, +:change_pin+, +:denied+.
|
|
301
|
+
* +true+ means that all authentication steps are returned as successful.
|
|
302
|
+
*
|
|
303
|
+
* Creates a new session. The session will talk to the RSA server configured via the
|
|
304
|
+
* RSA configuration associated with the installed library, or skip talking to the server
|
|
305
|
+
* entirely if in test mode.
|
|
306
|
+
*
|
|
307
|
+
*/
|
|
308
|
+
static VALUE securid_session_initialize(int argc, VALUE *argv, VALUE self)
|
|
309
|
+
{
|
|
310
|
+
securid_session_t *session;
|
|
311
|
+
VALUE session_data;
|
|
312
|
+
VALUE options = Qnil;
|
|
313
|
+
VALUE test_mode = Qfalse;
|
|
314
|
+
|
|
315
|
+
rb_scan_args(argc, argv, "0:", &options);
|
|
316
|
+
|
|
317
|
+
// Allocate a new securid_session_t and wrap it as a ruby object
|
|
318
|
+
session_data = TypedData_Make_Struct(rb_cData, securid_session_t, &securid_session_data_type, session);
|
|
319
|
+
session->handle = SDI_HANDLE_NONE;
|
|
320
|
+
|
|
321
|
+
// Stick our new securid_session_t into an instance variable on self
|
|
322
|
+
rb_ivar_set(self, securid_id_session, session_data);
|
|
323
|
+
|
|
324
|
+
// Initalize our status to nil
|
|
325
|
+
rb_ivar_set(self, securid_id_session_status, Qnil);
|
|
326
|
+
|
|
327
|
+
// Initalize our test_mode to the supplied option
|
|
328
|
+
if (!NIL_P(options))
|
|
329
|
+
{
|
|
330
|
+
test_mode = rb_hash_aref(options, rb_symTestMode);
|
|
331
|
+
}
|
|
332
|
+
rb_ivar_set(self, securid_id_session_test_mode, test_mode);
|
|
333
|
+
|
|
334
|
+
return self;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/*
|
|
338
|
+
* @overload authenticate(username, passcode)
|
|
339
|
+
* @param username [String] The username to authenticate with.
|
|
340
|
+
* @param passcode [String] The passcode to authenticate with. Passcodes are the user's pin concatenated
|
|
341
|
+
* with the current token value.
|
|
342
|
+
*
|
|
343
|
+
* Attempts to authenticate the user against the RSA ACE server using the username, pin, and token value.
|
|
344
|
+
* It will indicate if authentication fails due to token issue (pin change or resynchronization request),
|
|
345
|
+
* or a normal authentication failure (denied). The session object will have the returned status stored in
|
|
346
|
+
* its {#status status} attribute. A session with a status of {AUTHENTICATED} or
|
|
347
|
+
* {DENIED} can not be reused. A session with a status of {MUST_CHANGE_PIN} or
|
|
348
|
+
* {MUST_RESYNCHRONIZE} can be used to complete the required step, and then be used to reauthenticate
|
|
349
|
+
* with another call to {#authenticate}
|
|
350
|
+
*
|
|
351
|
+
* This method can only be called when the session state is {UNSTARTED}. Calling it in any other state
|
|
352
|
+
* will result in a {SecurIDError} being raised.
|
|
353
|
+
*
|
|
354
|
+
* @raise [SecurIDError] if the session is not in the {UNSTARTED} state or if an internal error occurs.
|
|
355
|
+
* @return [Symbol] The state of the authentication request, which is one of the constants {AUTHENTICATED},
|
|
356
|
+
* {DENIED}, {MUST_CHANGE_PIN}, or {MUST_RESYNCHRONIZE}.
|
|
357
|
+
*/
|
|
358
|
+
static VALUE securid_session_authenticate(VALUE self, VALUE username, VALUE passcode)
|
|
359
|
+
{
|
|
360
|
+
int return_value;
|
|
361
|
+
VALUE session_data;
|
|
362
|
+
VALUE status = Qnil;
|
|
363
|
+
securid_session_t *session;
|
|
364
|
+
SD_CHAR *username_str;
|
|
365
|
+
SD_CHAR *passcode_str;
|
|
366
|
+
|
|
367
|
+
// Check that we are in an allowed state
|
|
368
|
+
securid_session_check_status(self, (ID)0);
|
|
369
|
+
|
|
370
|
+
if (!securid_session_is_test_mode(self))
|
|
371
|
+
{
|
|
372
|
+
// Fetch our securid_session_t from self
|
|
373
|
+
session_data = rb_ivar_get(self, securid_id_session);
|
|
374
|
+
TypedData_Get_Struct(session_data, securid_session_t, &securid_session_data_type, session);
|
|
375
|
+
|
|
376
|
+
// Convert our arguments to C Strings
|
|
377
|
+
username_str = StringValueCStr(username);
|
|
378
|
+
passcode_str = StringValueCStr(passcode);
|
|
379
|
+
|
|
380
|
+
// Initalize the session handler
|
|
381
|
+
return_value = SD_Init(&session->handle);
|
|
382
|
+
if (return_value != ACM_OK)
|
|
383
|
+
{
|
|
384
|
+
rb_raise(rb_eSecurIDError, "Failed to initialize session handler - code %d", return_value);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Lock the username, part of the Two Step Authentication flow
|
|
388
|
+
return_value = SD_Lock(session->handle, username_str);
|
|
389
|
+
if (return_value != ACM_OK)
|
|
390
|
+
{
|
|
391
|
+
rb_raise(rb_eSecurIDError, "Failed to lock username - code %d", return_value);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
return_value = SD_Check(session->handle, passcode_str, username_str);
|
|
395
|
+
|
|
396
|
+
if (return_value == ACM_OK)
|
|
397
|
+
{
|
|
398
|
+
// We are authenticated
|
|
399
|
+
status = rb_const_get(rb_cRSASecurIDSession, securid_id_session_authenticated);
|
|
400
|
+
} else if (return_value == ACM_ACCESS_DENIED)
|
|
401
|
+
{
|
|
402
|
+
// We are denied
|
|
403
|
+
status = rb_const_get(rb_cRSASecurIDSession, securid_id_session_denied);
|
|
404
|
+
} else if (return_value == ACM_NEXT_CODE_REQUIRED)
|
|
405
|
+
{
|
|
406
|
+
// We need the user to resynchronize the token
|
|
407
|
+
status = rb_const_get(rb_cRSASecurIDSession, securid_id_session_resynchronize);
|
|
408
|
+
} else if (return_value == ACM_NEW_PIN_REQUIRED)
|
|
409
|
+
{
|
|
410
|
+
// We need the user to enter a new pin
|
|
411
|
+
status = rb_const_get(rb_cRSASecurIDSession, securid_id_session_change_pin);
|
|
412
|
+
} else
|
|
413
|
+
{
|
|
414
|
+
// Internal error of some sort
|
|
415
|
+
rb_raise(rb_eSecurIDError, "Failed to authenticate the user - code %d", return_value);
|
|
416
|
+
}
|
|
417
|
+
} else
|
|
418
|
+
{
|
|
419
|
+
if (securid_session_is_test_mode_resynchronize(self))
|
|
420
|
+
{
|
|
421
|
+
// Force resynchronize in resynchronization test mode
|
|
422
|
+
status = rb_const_get(rb_cRSASecurIDSession, securid_id_session_resynchronize);
|
|
423
|
+
} else if (securid_session_is_test_mode_change_pin(self))
|
|
424
|
+
{
|
|
425
|
+
// Force pin change in pin change test mode
|
|
426
|
+
status = rb_const_get(rb_cRSASecurIDSession, securid_id_session_change_pin);
|
|
427
|
+
} else if (securid_session_is_test_mode_denied(self))
|
|
428
|
+
{
|
|
429
|
+
// Force denied in denied test mode
|
|
430
|
+
status = rb_const_get(rb_cRSASecurIDSession, securid_id_session_denied);
|
|
431
|
+
} else
|
|
432
|
+
{
|
|
433
|
+
// Force success in test mode
|
|
434
|
+
status = rb_const_get(rb_cRSASecurIDSession, securid_id_session_authenticated);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// Update our status
|
|
439
|
+
rb_ivar_set(self, securid_id_session_status, status);
|
|
440
|
+
|
|
441
|
+
return status;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/*
|
|
445
|
+
* @overload change_pin(pin)
|
|
446
|
+
* @param pin [String] The new pin for the token.
|
|
447
|
+
*
|
|
448
|
+
* Changes the pin associated with the token. This method can only be called when the
|
|
449
|
+
* session is in the {MUST_CHANGE_PIN} state. Calling it in any other state will result
|
|
450
|
+
* in a {SecurIDError} being raised. After calling {#change_pin}, the session state is
|
|
451
|
+
* reset to {UNSTARTED}. A subsequent call to {#authenticate} is needed to actually
|
|
452
|
+
* authenticate the user.
|
|
453
|
+
*
|
|
454
|
+
* The typical flow for chaning the pin is first call {#authenticate} with the old pin,
|
|
455
|
+
* see that we are in the {MUST_CHANGE_PIN} state, call {#change_pin} to with the new
|
|
456
|
+
* pin, then call {#authenticate} with the new pin to finally authorize the user.
|
|
457
|
+
*
|
|
458
|
+
*
|
|
459
|
+
* @raise [SecurIDError] if the session is not in the {MUST_CHANGE_PIN} state, if an
|
|
460
|
+
* internal error occurs, or the change request fails.
|
|
461
|
+
* @return [true] Always returns +true+ or raises an error.
|
|
462
|
+
*/
|
|
463
|
+
static VALUE securid_session_change_pin(VALUE self, VALUE pin)
|
|
464
|
+
{
|
|
465
|
+
VALUE session_data;
|
|
466
|
+
securid_session_t *session;
|
|
467
|
+
SD_CHAR *pin_str;
|
|
468
|
+
int return_value;
|
|
469
|
+
|
|
470
|
+
// Check that we are in an allowed state
|
|
471
|
+
securid_session_check_status(self, securid_id_session_change_pin);
|
|
472
|
+
|
|
473
|
+
if (!securid_session_is_test_mode(self))
|
|
474
|
+
{
|
|
475
|
+
// Fetch our securid_session_t from self
|
|
476
|
+
session_data = rb_ivar_get(self, securid_id_session);
|
|
477
|
+
TypedData_Get_Struct(session_data, securid_session_t, &securid_session_data_type, session);
|
|
478
|
+
|
|
479
|
+
// Convert our arguments to C Strings
|
|
480
|
+
pin_str = StringValueCStr(pin);
|
|
481
|
+
|
|
482
|
+
return_value = SD_Pin(session->handle, pin_str);
|
|
483
|
+
if (return_value != ACM_NEW_PIN_ACCEPTED)
|
|
484
|
+
{
|
|
485
|
+
// Changing pin failed for internal reasons
|
|
486
|
+
rb_raise(rb_eSecurIDError, "Failed to change the pin - code %d", return_value);
|
|
487
|
+
}
|
|
488
|
+
} else
|
|
489
|
+
{
|
|
490
|
+
if (securid_session_is_test_mode_change_pin(self))
|
|
491
|
+
{
|
|
492
|
+
// exit pin change test mode for regular test mode
|
|
493
|
+
rb_ivar_set(self, securid_id_session_test_mode, Qtrue);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// Update our status to be unstarted.
|
|
498
|
+
rb_ivar_set(self, securid_id_session_status, Qnil);
|
|
499
|
+
|
|
500
|
+
return Qtrue;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/*
|
|
504
|
+
* Cancels a pin change request. On success the session state will be set back to {UNSTARTED}.
|
|
505
|
+
* This method can only be called when the session is in the {MUST_CHANGE_PIN} state. Calling
|
|
506
|
+
* it in any other state will raise a {SecurIDError}.
|
|
507
|
+
*
|
|
508
|
+
*
|
|
509
|
+
* @raise [SecurIDError] if the session is not in the {MUST_CHANGE_PIN} state, if an internal
|
|
510
|
+
* error occurs, or if the the canceling fails.
|
|
511
|
+
* @return [true] Always returns +true+ or raises an error.
|
|
512
|
+
*/
|
|
513
|
+
static VALUE securid_session_cancel_pin(VALUE self)
|
|
514
|
+
{
|
|
515
|
+
VALUE session_data;
|
|
516
|
+
securid_session_t *session;
|
|
517
|
+
SD_CHAR *pin_str;
|
|
518
|
+
int return_value;
|
|
519
|
+
|
|
520
|
+
// Check that we are in an allowed state
|
|
521
|
+
securid_session_check_status(self, securid_id_session_change_pin);
|
|
522
|
+
|
|
523
|
+
if (!securid_session_is_test_mode(self))
|
|
524
|
+
{
|
|
525
|
+
// Fetch our securid_session_t from self
|
|
526
|
+
session_data = rb_ivar_get(self, securid_id_session);
|
|
527
|
+
TypedData_Get_Struct(session_data, securid_session_t, &securid_session_data_type, session);
|
|
528
|
+
|
|
529
|
+
return_value = SD_Pin(session->handle, NULL);
|
|
530
|
+
if (return_value != ACM_NEW_PIN_ACCEPTED)
|
|
531
|
+
{
|
|
532
|
+
rb_raise(rb_eSecurIDError, "Failed to cancel changing the pin - code %d", return_value);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// Update our status to be unstarted.
|
|
537
|
+
rb_ivar_set(self, securid_id_session_status, Qnil);
|
|
538
|
+
|
|
539
|
+
return Qtrue;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/*
|
|
543
|
+
* @overload resynchronize(passcode)
|
|
544
|
+
* @param passcode [String] The user's pin concatenated with the _next_ token value.
|
|
545
|
+
*
|
|
546
|
+
* Completes the token resynchronize flow. This method should be called when the server is requesting the user
|
|
547
|
+
* to resynchronize their token. It is not possible to initiate a resychronization request with this method. The
|
|
548
|
+
* session must be in the {MUST_RESYNCHRONIZE} state. Callig it in any other state will raise a {SecurIDError}.
|
|
549
|
+
*
|
|
550
|
+
*
|
|
551
|
+
* @raise [SecurIDError] if the session is not in the {MUST_RESYNCHRONIZE} state or the resynchronization fails
|
|
552
|
+
* for any reason other than the passcode not matching.
|
|
553
|
+
* @return [Symbol] Either {AUTHENTICATED} or {DENIED} depending on if the resynchronization was successful.
|
|
554
|
+
*/
|
|
555
|
+
static VALUE securid_session_resynchronize(VALUE self, VALUE passcode)
|
|
556
|
+
{
|
|
557
|
+
int return_value;
|
|
558
|
+
VALUE session_data;
|
|
559
|
+
VALUE status;
|
|
560
|
+
securid_session_t *session;
|
|
561
|
+
SD_CHAR *passcode_str;
|
|
562
|
+
|
|
563
|
+
// Check that we are in an allowed state
|
|
564
|
+
securid_session_check_status(self, securid_id_session_resynchronize);
|
|
565
|
+
|
|
566
|
+
if (!securid_session_is_test_mode(self))
|
|
567
|
+
{
|
|
568
|
+
// Fetch our securid_session_t from self
|
|
569
|
+
session_data = rb_ivar_get(self, securid_id_session);
|
|
570
|
+
TypedData_Get_Struct(session_data, securid_session_t, &securid_session_data_type, session);
|
|
571
|
+
|
|
572
|
+
// Convert our arguments to C Strings
|
|
573
|
+
passcode_str = StringValueCStr(passcode);
|
|
574
|
+
|
|
575
|
+
// Initalize the session handler
|
|
576
|
+
return_value = SD_Next(session->handle, passcode_str);
|
|
577
|
+
if (return_value == ACM_OK)
|
|
578
|
+
{
|
|
579
|
+
// We are authenticated
|
|
580
|
+
status = rb_const_get(rb_cRSASecurIDSession, securid_id_session_authenticated);
|
|
581
|
+
} else if (return_value == ACM_ACCESS_DENIED)
|
|
582
|
+
{
|
|
583
|
+
// We are denied
|
|
584
|
+
status = rb_const_get(rb_cRSASecurIDSession, securid_id_session_denied);
|
|
585
|
+
} else {
|
|
586
|
+
// Internal error of some sort
|
|
587
|
+
rb_raise(rb_eSecurIDError, "Failed to synchronize the token - code %d", return_value);
|
|
588
|
+
}
|
|
589
|
+
} else {
|
|
590
|
+
if (securid_session_is_test_mode_resynchronize(self))
|
|
591
|
+
{
|
|
592
|
+
// exit resynchronization test mode for regular test mode
|
|
593
|
+
rb_ivar_set(self, securid_id_session_test_mode, Qtrue);
|
|
594
|
+
}
|
|
595
|
+
// Force success in test mode
|
|
596
|
+
status = rb_const_get(rb_cRSASecurIDSession, securid_id_session_authenticated);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// Update our status
|
|
600
|
+
rb_ivar_set(self, securid_id_session_status, status);
|
|
601
|
+
|
|
602
|
+
return status;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
/*
|
|
607
|
+
* Fetches the status of the RSA agent. This includes details about the RSA ACE server
|
|
608
|
+
* the agent is communicating with. *NOTE:* this method can not be called in test mode
|
|
609
|
+
* unless there is an actual RSA agent present. The returned status hash is a ruby
|
|
610
|
+
* version of the +S_status_display+ struct populated by +AceAgentStatusDisplay+, and
|
|
611
|
+
* any questions about the meaning of its fields should be directed there.
|
|
612
|
+
*
|
|
613
|
+
* @example Returned Status Hash
|
|
614
|
+
* {
|
|
615
|
+
* config_version: 15,
|
|
616
|
+
* max_servers: 1,
|
|
617
|
+
* max_replicas: 4,
|
|
618
|
+
* max_retries: 5,
|
|
619
|
+
* base_timeout: 5,
|
|
620
|
+
* use_des: 1,
|
|
621
|
+
* trusted: 0,
|
|
622
|
+
* port: 5500,
|
|
623
|
+
* service_protocol_version: 0,
|
|
624
|
+
* service_name: "securid",
|
|
625
|
+
* service_protocol: "udp",
|
|
626
|
+
* server_release_number: {
|
|
627
|
+
* major: 0,
|
|
628
|
+
* minor: 0,
|
|
629
|
+
* patch: 0,
|
|
630
|
+
* build: 0
|
|
631
|
+
* },
|
|
632
|
+
* servers: [
|
|
633
|
+
* {
|
|
634
|
+
* hostname: "rsa.example.com",
|
|
635
|
+
* address: "192.168.0.1",
|
|
636
|
+
* active_address: nil,
|
|
637
|
+
* aliases: [],
|
|
638
|
+
* display_status: {
|
|
639
|
+
* primary: true,
|
|
640
|
+
* master: true,
|
|
641
|
+
* slave: false,
|
|
642
|
+
* selectable: false,
|
|
643
|
+
* emergency: false,
|
|
644
|
+
* suspended: true
|
|
645
|
+
* }
|
|
646
|
+
* },
|
|
647
|
+
* {
|
|
648
|
+
* hostname: nil,
|
|
649
|
+
* address: "192.168.0.2",
|
|
650
|
+
* active_address: nil,
|
|
651
|
+
* aliases: [],
|
|
652
|
+
* display_status: {
|
|
653
|
+
* primary: false,
|
|
654
|
+
* master: false,
|
|
655
|
+
* slave: false,
|
|
656
|
+
* selectable: false,
|
|
657
|
+
* emergency: false,
|
|
658
|
+
* suspended: true
|
|
659
|
+
* }
|
|
660
|
+
* }
|
|
661
|
+
* ]
|
|
662
|
+
* }
|
|
663
|
+
*
|
|
664
|
+
* @raise [SecurIDError] if the RSA agent failed to initialize.
|
|
665
|
+
* @return [Hash] The status hash, keyed by symbols.
|
|
666
|
+
*/
|
|
667
|
+
static VALUE securid_agent_status(VALUE self) {
|
|
668
|
+
VALUE status = Qfalse;
|
|
669
|
+
VALUE server_release_number;
|
|
670
|
+
VALUE server_details;
|
|
671
|
+
VALUE servers;
|
|
672
|
+
VALUE server_aliases;
|
|
673
|
+
VALUE display_status;
|
|
674
|
+
S_status_display agent_status;
|
|
675
|
+
DISP_SRVR_INFO * server_info;
|
|
676
|
+
int return_value, i, j, str_length;
|
|
677
|
+
struct in_addr addr;
|
|
678
|
+
|
|
679
|
+
// Initialize the library. Safe to call multiple times.
|
|
680
|
+
if (AceInitialize() != SD_TRUE) {
|
|
681
|
+
rb_raise(rb_eSecurIDError, "Failed to initialize authentication agent");
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// Make sure we are zero'd
|
|
685
|
+
memset(&agent_status, 0, sizeof(agent_status));
|
|
686
|
+
// Set the struct size so the SDK can identify the version used
|
|
687
|
+
agent_status.u32Size = (SD_U32) sizeof(agent_status);
|
|
688
|
+
// Fetch the agent status
|
|
689
|
+
return_value = AceAgentStatusDisplay(&agent_status);
|
|
690
|
+
|
|
691
|
+
if (return_value == ACE_SUCCESS) {
|
|
692
|
+
status = rb_hash_new();
|
|
693
|
+
|
|
694
|
+
// Populate status hash
|
|
695
|
+
rb_hash_aset(status, rb_symConfigVersion, INT2NUM(agent_status.config_version));
|
|
696
|
+
rb_hash_aset(status, rb_symMaxServers, INT2NUM(agent_status.acmmaxservers));
|
|
697
|
+
rb_hash_aset(status, rb_symMaxReplicas, INT2NUM(agent_status.acmmaxreplicas));
|
|
698
|
+
rb_hash_aset(status, rb_symMaxRetries, INT2NUM(agent_status.acmmaxretries));
|
|
699
|
+
rb_hash_aset(status, rb_symBaseTimeout, INT2NUM(agent_status.acmbasetimeout));
|
|
700
|
+
rb_hash_aset(status, rb_symUseDES, INT2NUM(agent_status.use_des));
|
|
701
|
+
rb_hash_aset(status, rb_symTrusted, INT2NUM(agent_status.trusted));
|
|
702
|
+
rb_hash_aset(status, rb_symPort, INT2NUM(agent_status.acmport));
|
|
703
|
+
rb_hash_aset(status, rb_symServiceProtocolVersion, INT2NUM(agent_status.server_hi_protocol));
|
|
704
|
+
|
|
705
|
+
str_length = strnlen(agent_status.acmservice, sizeof(agent_status.acmservice) / sizeof(SD_CHAR));
|
|
706
|
+
rb_hash_aset(status, rb_symServiceName, rb_str_new(agent_status.acmservice, str_length));
|
|
707
|
+
|
|
708
|
+
str_length = strnlen(agent_status.acmprotocol, sizeof(agent_status.acmprotocol) / sizeof(SD_CHAR));
|
|
709
|
+
rb_hash_aset(status, rb_symServiceProtocol, rb_str_new(agent_status.acmprotocol, str_length));
|
|
710
|
+
|
|
711
|
+
// Populate release number hash
|
|
712
|
+
server_release_number = rb_hash_new();
|
|
713
|
+
rb_hash_aset(server_release_number, rb_symMajor, INT2NUM(agent_status.server_release_from_server[0]));
|
|
714
|
+
rb_hash_aset(server_release_number, rb_symMinor, INT2NUM(agent_status.server_release_from_server[1]));
|
|
715
|
+
rb_hash_aset(server_release_number, rb_symPatch, INT2NUM(agent_status.server_release_from_server[2]));
|
|
716
|
+
rb_hash_aset(server_release_number, rb_symBuild, INT2NUM(agent_status.server_release_from_server[3]));
|
|
717
|
+
rb_hash_aset(status, rb_symServerReleaseNumber, server_release_number);
|
|
718
|
+
|
|
719
|
+
servers = rb_ary_new();
|
|
720
|
+
|
|
721
|
+
// Populate server array
|
|
722
|
+
for (i = 0; i < agent_status.acmmaxreplicas; ++i) {
|
|
723
|
+
server_info = &agent_status.acm_servers[i];
|
|
724
|
+
|
|
725
|
+
if (!(server_info->addr && server_info->hostname)) {
|
|
726
|
+
continue;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
server_details = rb_hash_new();
|
|
730
|
+
|
|
731
|
+
str_length = strnlen(server_info->hostname, DISP_LENHOSTNAME);
|
|
732
|
+
rb_hash_aset(server_details, rb_symHostname, str_length ? rb_str_new(server_info->hostname, str_length) : Qnil);
|
|
733
|
+
|
|
734
|
+
addr.s_addr = server_info->addr;
|
|
735
|
+
rb_hash_aset(server_details, rb_symAddress, server_info->addr ? rb_str_new2(inet_ntoa(addr)) : Qnil);
|
|
736
|
+
|
|
737
|
+
addr.s_addr = server_info->active_addr;
|
|
738
|
+
rb_hash_aset(server_details, rb_symActiveAddress, server_info->active_addr ? rb_str_new2(inet_ntoa(addr)) : Qnil);
|
|
739
|
+
|
|
740
|
+
// build server aliases array
|
|
741
|
+
server_aliases = rb_ary_new();
|
|
742
|
+
for (j = 0; j < DISP_MAXALIASES; ++j) {
|
|
743
|
+
if (!server_info->aliases[j]) {
|
|
744
|
+
continue;
|
|
745
|
+
}
|
|
746
|
+
addr.s_addr = server_info->aliases[j];
|
|
747
|
+
rb_ary_push(server_aliases, rb_str_new2(inet_ntoa(addr)));
|
|
748
|
+
}
|
|
749
|
+
rb_hash_aset(server_details, rb_symAliases, server_aliases);
|
|
750
|
+
|
|
751
|
+
display_status = rb_hash_new();
|
|
752
|
+
rb_hash_aset(display_status, rb_symPrimary, CTEST(server_info->display_status & DISP_STATUS_PRIMARY));
|
|
753
|
+
rb_hash_aset(display_status, rb_symMaster, CTEST(server_info->display_status & DISP_MSTR_SLAVE && i == 0));
|
|
754
|
+
rb_hash_aset(display_status, rb_symSlave, CTEST(server_info->display_status & DISP_MSTR_SLAVE && i > 0));
|
|
755
|
+
rb_hash_aset(display_status, rb_symSelectable, CTEST(server_info->display_status & DISP_STATUS_SELECTABLE));
|
|
756
|
+
rb_hash_aset(display_status, rb_symEmergency, CTEST(server_info->display_status & DISP_STATUS_EMERGENCY));
|
|
757
|
+
rb_hash_aset(display_status, rb_symSuspended, CTEST(server_info->display_status & DISP_STATUS_SUSPENDED));
|
|
758
|
+
rb_hash_aset(server_details, rb_symDisplayStatus, display_status);
|
|
759
|
+
|
|
760
|
+
// Add server details to servers array
|
|
761
|
+
rb_ary_push(servers, server_details);
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// Add servers array to status hash
|
|
765
|
+
rb_hash_aset(status, rb_symServers, servers);
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
return status;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
void Init_securid()
|
|
772
|
+
{
|
|
773
|
+
securid_id_session = rb_intern("session_handler"); // hidden from the ruby runtime due to its name
|
|
774
|
+
securid_id_session_status = rb_intern("@status");
|
|
775
|
+
securid_id_session_test_mode = rb_intern("@test_mode");
|
|
776
|
+
securid_id_session_authenticated = rb_intern("AUTHENTICATED");
|
|
777
|
+
securid_id_session_denied = rb_intern("DENIED");
|
|
778
|
+
securid_id_session_change_pin = rb_intern("MUST_CHANGE_PIN");
|
|
779
|
+
securid_id_session_resynchronize = rb_intern("MUST_RESYNCHRONIZE");
|
|
780
|
+
rb_symTestMode = ID2SYM(rb_intern("test_mode"));
|
|
781
|
+
rb_symResynchronize = ID2SYM(rb_intern("resynchronize"));
|
|
782
|
+
rb_symChangePin = ID2SYM(rb_intern("change_pin"));
|
|
783
|
+
rb_symDenied = ID2SYM(rb_intern("denied"));
|
|
784
|
+
|
|
785
|
+
rb_symConfigVersion = ID2SYM(rb_intern("config_version"));
|
|
786
|
+
rb_symMaxServers = ID2SYM(rb_intern("max_servers"));
|
|
787
|
+
rb_symMaxReplicas = ID2SYM(rb_intern("max_replicas"));
|
|
788
|
+
rb_symMaxRetries = ID2SYM(rb_intern("max_retries"));
|
|
789
|
+
rb_symBaseTimeout = ID2SYM(rb_intern("base_timeout"));
|
|
790
|
+
rb_symUseDES = ID2SYM(rb_intern("use_des"));
|
|
791
|
+
rb_symTrusted = ID2SYM(rb_intern("trusted"));
|
|
792
|
+
rb_symPort = ID2SYM(rb_intern("port"));
|
|
793
|
+
rb_symServiceName = ID2SYM(rb_intern("service_name"));
|
|
794
|
+
rb_symServiceProtocol = ID2SYM(rb_intern("service_protocol"));
|
|
795
|
+
rb_symServiceProtocolVersion = ID2SYM(rb_intern("service_protocol_version"));
|
|
796
|
+
rb_symServerReleaseNumber = ID2SYM(rb_intern("server_release_number"));
|
|
797
|
+
rb_symServers = ID2SYM(rb_intern("servers"));
|
|
798
|
+
rb_symMajor = ID2SYM(rb_intern("major"));
|
|
799
|
+
rb_symMinor = ID2SYM(rb_intern("minor"));
|
|
800
|
+
rb_symPatch = ID2SYM(rb_intern("patch"));
|
|
801
|
+
rb_symBuild = ID2SYM(rb_intern("build"));
|
|
802
|
+
rb_symAddress = ID2SYM(rb_intern("address"));
|
|
803
|
+
rb_symActiveAddress = ID2SYM(rb_intern("active_address"));
|
|
804
|
+
rb_symAliases = ID2SYM(rb_intern("aliases"));
|
|
805
|
+
rb_symDisplayStatus = ID2SYM(rb_intern("display_status"));
|
|
806
|
+
rb_symHostname = ID2SYM(rb_intern("hostname"));
|
|
807
|
+
rb_symPrimary = ID2SYM(rb_intern("primary"));
|
|
808
|
+
rb_symMaster = ID2SYM(rb_intern("master"));
|
|
809
|
+
rb_symSlave = ID2SYM(rb_intern("slave"));
|
|
810
|
+
rb_symSelectable = ID2SYM(rb_intern("selectable"));
|
|
811
|
+
rb_symEmergency = ID2SYM(rb_intern("emergency"));
|
|
812
|
+
rb_symSuspended = ID2SYM(rb_intern("suspended"));
|
|
813
|
+
rb_symAddressVerified = ID2SYM(rb_intern("address_verified"));
|
|
814
|
+
|
|
815
|
+
// module RSA
|
|
816
|
+
rb_mRSA = rb_define_module("RSA");
|
|
817
|
+
|
|
818
|
+
// module RSA::SecurID
|
|
819
|
+
rb_mRSASecurID = rb_define_module_under(rb_mRSA, "SecurID");
|
|
820
|
+
|
|
821
|
+
/*
|
|
822
|
+
* Document-class: RSA::SecurID::SecurIDError
|
|
823
|
+
*
|
|
824
|
+
* The error class used by the {Session} class to indicate internal state or communication
|
|
825
|
+
* errors. Error codes found in the messages can be referenced against the RSA SDK
|
|
826
|
+
* documentation.
|
|
827
|
+
*
|
|
828
|
+
*/
|
|
829
|
+
rb_eSecurIDError = rb_define_class_under(rb_mRSASecurID, "SecurIDError", rb_eStandardError);
|
|
830
|
+
|
|
831
|
+
// def RSA::SecurID.authenticate(username, passcode)
|
|
832
|
+
rb_define_module_function(rb_mRSASecurID, "authenticate", securid_authenticate, 2);
|
|
833
|
+
|
|
834
|
+
// def RSA::SecurID.agent_status
|
|
835
|
+
rb_define_module_function(rb_mRSASecurID, "agent_status", securid_agent_status, 0);
|
|
836
|
+
|
|
837
|
+
// class RSA::SecurID::Session
|
|
838
|
+
rb_cRSASecurIDSession = rb_define_class_under(rb_mRSASecurID, "Session", rb_cObject);
|
|
839
|
+
|
|
840
|
+
// def RSA::SecurID::Session.new
|
|
841
|
+
rb_define_method(rb_cRSASecurIDSession, "initialize", securid_session_initialize, -1);
|
|
842
|
+
|
|
843
|
+
// def RSA::SecurID::Session#authenticate(username, passcode)
|
|
844
|
+
rb_define_method(rb_cRSASecurIDSession, "authenticate", securid_session_authenticate, 2);
|
|
845
|
+
|
|
846
|
+
// def RSA::SecurID::Session#change_pin(pin)
|
|
847
|
+
rb_define_method(rb_cRSASecurIDSession, "change_pin", securid_session_change_pin, 1);
|
|
848
|
+
|
|
849
|
+
// def RSA::SecurID::Session#cancel_pin
|
|
850
|
+
rb_define_method(rb_cRSASecurIDSession, "cancel_pin", securid_session_cancel_pin, 0);
|
|
851
|
+
|
|
852
|
+
// def RSA::SecurID::Session#resynchronize
|
|
853
|
+
rb_define_method(rb_cRSASecurIDSession, "resynchronize", securid_session_resynchronize, 1);
|
|
142
854
|
}
|
data/lib/securid.rb
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require 'securid/securid'
|
|
2
|
+
|
|
3
|
+
module RSA
|
|
4
|
+
module SecurID
|
|
5
|
+
|
|
6
|
+
# Manages a single authentication session against the RSA ACE server. Handles the various life cycle
|
|
7
|
+
# events that may occur, such as token resynchronization and pin changes. Includes a test mode that can
|
|
8
|
+
# simulate various responses when an ACE server is not present (for example during local development).
|
|
9
|
+
# Instances of this class should not be reused unless the RSA flow (and this documentation) indicates
|
|
10
|
+
# otherwise (for example, you can issue an {#authenticate} call after a successful {#change_pin} call).
|
|
11
|
+
#
|
|
12
|
+
# This class assumes you have an understanding of the RSA authentication flow. Timeouts on state
|
|
13
|
+
# transitions are enforced by the server, and are not documented here as they may change between ACE
|
|
14
|
+
# releases.
|
|
15
|
+
#
|
|
16
|
+
# In test mode, this class will send no network traffic and not talk to the RSA agent. The RSA SDK
|
|
17
|
+
# libraries do not even need to be present, just the header files. In the normal mode, the server
|
|
18
|
+
# configuration is imported by the agent directly.
|
|
19
|
+
class Session
|
|
20
|
+
|
|
21
|
+
# Returns the current state of the session, which is one of {AUTHENTICATED}, {DENIED},
|
|
22
|
+
# {MUST_CHANGE_PIN}, {MUST_RESYNCHRONIZE}, or {UNSTARTED}.
|
|
23
|
+
attr_reader :status
|
|
24
|
+
|
|
25
|
+
AUTHENTICATED = :authenticated
|
|
26
|
+
DENIED = :denied
|
|
27
|
+
MUST_CHANGE_PIN = :must_change_pin
|
|
28
|
+
MUST_RESYNCHRONIZE = :must_resynchronize
|
|
29
|
+
UNSTARTED = nil
|
|
30
|
+
|
|
31
|
+
# @return [Boolean] +true+ if the session is in the {MUST_RESYNCHRONIZE} state, +false+ otherwise.
|
|
32
|
+
# Checks if the session is in the {MUST_RESYNCHRONIZE} state.
|
|
33
|
+
def resynchronize?
|
|
34
|
+
@status == MUST_RESYNCHRONIZE
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Checks if the session is in the {MUST_CHANGE_PIN} state.
|
|
38
|
+
# @return [Boolean] +true+ if the session is in the {MUST_CHANGE_PIN} state, +false+ otherwise.
|
|
39
|
+
def change_pin?
|
|
40
|
+
@status == MUST_CHANGE_PIN
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Checks if the session is in the {AUTHENTICATED} state.
|
|
44
|
+
# @return [Boolean] +true+ if the session is in the {AUTHENTICATED} state, +false+ otherwise.
|
|
45
|
+
def authenticated?
|
|
46
|
+
@status == AUTHENTICATED
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Checks if the session is in the {DENIED} state.
|
|
50
|
+
# @return [Boolean] +true+ if the session is in the {DENIED} state, +false+ otherwise.
|
|
51
|
+
def denied?
|
|
52
|
+
@status == DENIED
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
metadata
CHANGED
|
@@ -1,67 +1,52 @@
|
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: securid
|
|
3
|
-
version: !ruby/object:Gem::Version
|
|
4
|
-
|
|
5
|
-
prerelease: false
|
|
6
|
-
segments:
|
|
7
|
-
- 0
|
|
8
|
-
- 1
|
|
9
|
-
version: "0.1"
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.2.5
|
|
10
5
|
platform: ruby
|
|
11
|
-
authors:
|
|
6
|
+
authors:
|
|
12
7
|
- Ian Lesperance
|
|
8
|
+
- Edward Holets
|
|
13
9
|
autorequire:
|
|
14
10
|
bindir: bin
|
|
15
11
|
cert_chain: []
|
|
16
|
-
|
|
17
|
-
date: 2010-06-10 00:00:00 -07:00
|
|
18
|
-
default_executable:
|
|
12
|
+
date: 2016-03-14 00:00:00.000000000 Z
|
|
19
13
|
dependencies: []
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
description: A library for authenticating with an RSA SecurID ACE Authentication Server.
|
|
15
|
+
Supports synchronous authenttication with ACE Server 6.1 and greater. Supports interactive
|
|
16
|
+
and non-interactive flows.
|
|
22
17
|
email: ilesperance@ezpublishing.com
|
|
23
18
|
executables: []
|
|
24
|
-
|
|
25
|
-
extensions:
|
|
19
|
+
extensions:
|
|
26
20
|
- ext/securid/extconf.rb
|
|
27
21
|
extra_rdoc_files: []
|
|
28
|
-
|
|
29
|
-
files:
|
|
30
|
-
- ext/securid/securid.c
|
|
22
|
+
files:
|
|
31
23
|
- ext/securid/extconf.rb
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
24
|
+
- ext/securid/securid.c
|
|
25
|
+
- ext/securid/securid.h
|
|
26
|
+
- lib/securid.rb
|
|
27
|
+
homepage: http://github.com/sendstream/securid
|
|
28
|
+
licenses:
|
|
29
|
+
- MIT
|
|
30
|
+
metadata: {}
|
|
36
31
|
post_install_message:
|
|
37
32
|
rdoc_options: []
|
|
38
|
-
|
|
39
|
-
require_paths:
|
|
33
|
+
require_paths:
|
|
40
34
|
- lib
|
|
41
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
|
42
|
-
|
|
43
|
-
requirements:
|
|
35
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
44
37
|
- - ">="
|
|
45
|
-
- !ruby/object:Gem::Version
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
version: "0"
|
|
50
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
51
|
-
none: false
|
|
52
|
-
requirements:
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '0'
|
|
40
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
41
|
+
requirements:
|
|
53
42
|
- - ">="
|
|
54
|
-
- !ruby/object:Gem::Version
|
|
55
|
-
|
|
56
|
-
segments:
|
|
57
|
-
- 0
|
|
58
|
-
version: "0"
|
|
43
|
+
- !ruby/object:Gem::Version
|
|
44
|
+
version: '0'
|
|
59
45
|
requirements: []
|
|
60
|
-
|
|
61
46
|
rubyforge_project:
|
|
62
|
-
rubygems_version:
|
|
47
|
+
rubygems_version: 2.2.2
|
|
63
48
|
signing_key:
|
|
64
|
-
specification_version:
|
|
49
|
+
specification_version: 4
|
|
65
50
|
summary: A library for authenticating with an RSA SecurID ACE Authentication Server
|
|
66
51
|
test_files: []
|
|
67
|
-
|
|
52
|
+
has_rdoc:
|