vacman_controller 0.2.2 → 0.5.0
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 +5 -5
- data/ext/vacman_controller/extconf.rb +2 -2
- data/ext/vacman_controller/{vacman_controller.c → low_level.c} +193 -138
- data/lib/vacman_controller.rb +51 -167
- data/lib/vacman_controller/error.rb +16 -0
- data/lib/vacman_controller/kernel.rb +71 -0
- data/lib/vacman_controller/token.rb +182 -0
- data/lib/vacman_controller/token/properties.rb +193 -0
- metadata +40 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5ddbe7c0b1cf7bc1f64efa3ffa86ea66925dbdb27afa2f68434f0acfd3493fb8
|
4
|
+
data.tar.gz: cf653c109a8ba1bebdae0ecbdef5662978a05e56bfab0ee8a9f223ebc922d6fc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e81eed72afeda1a0d31053e55cc3eeaa7274e6324f02f8eb528361edd285e61a9a5e15b6a0de21abc8a1659c143f8dfcc93a449c6ebfa61f55e1cbf3aee2b13c
|
7
|
+
data.tar.gz: 97857b1596694fd6d40ff34aa8aad9b88b273b62fe69e2c5d90320c83fd21772599add8ce3f69a8e6094f5b03eed4d90c568fc78c923f9313951b71c8655f9a0
|
@@ -17,8 +17,8 @@ append_cflags "-I#{VACMAN_CONTROLLER}/include -Wall -std=c99 -Wno-declaration-af
|
|
17
17
|
append_ldflags "-L#{VACMAN_CONTROLLER}/lib -laal2sdk -Wl,-rpath #{VACMAN_CONTROLLER}/lib"
|
18
18
|
|
19
19
|
if find_library('aal2sdk', 'AAL2DPXInit', "#{VACMAN_CONTROLLER}/lib")
|
20
|
-
create_makefile('vacman_controller/
|
21
|
-
|
20
|
+
create_makefile('vacman_controller/low_level')
|
21
|
+
else
|
22
22
|
puts "No libaal2sdk found"
|
23
23
|
exit 1
|
24
24
|
end
|
@@ -1,60 +1,79 @@
|
|
1
|
+
/*
|
2
|
+
* Vacman Controller wrapper
|
3
|
+
*
|
4
|
+
* This Ruby Extension wraps the VASCO Vacman Controller
|
5
|
+
* library and makes its API accessible to Ruby code.
|
6
|
+
*
|
7
|
+
* (C) 2013 https://github.com/mlankenau
|
8
|
+
* (C) 2019 m.barnaba@ifad.org
|
9
|
+
*/
|
10
|
+
|
1
11
|
#include <ruby.h>
|
2
12
|
#include <string.h>
|
3
13
|
#include <aal2sdk.h>
|
4
14
|
|
5
|
-
|
6
|
-
|
15
|
+
|
16
|
+
/* The Vacman default kernel parameters, set up upon extension initialisation. */
|
17
|
+
TKernelParms g_KernelParms;
|
18
|
+
|
19
|
+
/* Ruby exception type, defined as VacmanController::Error in Ruby land. */
|
20
|
+
static VALUE e_VacmanError;
|
21
|
+
|
7
22
|
|
8
23
|
/*
|
9
|
-
*
|
24
|
+
* Raises an Error, decoding the Vacman Controller error code.
|
10
25
|
*/
|
11
|
-
static void
|
12
|
-
aat_ascii
|
13
|
-
|
14
|
-
|
26
|
+
static void vacman_library_error(const char* method, int vacman_error_code) {
|
27
|
+
aat_ascii vacman_error_message[100]; // Recommended value in documentation.
|
28
|
+
|
29
|
+
AAL2GetErrorMsg(vacman_error_code, vacman_error_message);
|
30
|
+
|
31
|
+
char error_message[256];
|
32
|
+
snprintf(error_message, 255, "%s error %d: %s", method, vacman_error_code,
|
33
|
+
vacman_error_message);
|
34
|
+
|
35
|
+
VALUE exc = rb_exc_new2(e_VacmanError, error_message);
|
36
|
+
rb_iv_set(exc, "@library_method", rb_str_new2(method));
|
37
|
+
rb_iv_set(exc, "@error_code", INT2FIX(vacman_error_code));
|
38
|
+
rb_iv_set(exc, "@error_message", rb_str_new2(vacman_error_message));
|
39
|
+
|
40
|
+
rb_exc_raise(exc);
|
15
41
|
}
|
16
42
|
|
17
43
|
|
18
44
|
/*
|
19
|
-
*
|
45
|
+
* Use AAL2GetLibraryVersion to obtain library version and return it as a Ruby Hash
|
20
46
|
*/
|
21
|
-
static VALUE
|
22
|
-
|
47
|
+
static VALUE vacman_library_version(VALUE module) {
|
48
|
+
aat_ascii version[16];
|
49
|
+
aat_int32 version_len = sizeof(version);
|
23
50
|
|
24
|
-
|
25
|
-
|
26
|
-
return Qnil;
|
27
|
-
}
|
51
|
+
aat_ascii bitness[4];
|
52
|
+
aat_int32 bitness_len = sizeof(bitness);
|
28
53
|
|
29
|
-
|
30
|
-
|
31
|
-
return Qnil;
|
32
|
-
}
|
54
|
+
aat_ascii type[8];
|
55
|
+
aat_int32 type_len = sizeof(type);
|
33
56
|
|
34
|
-
|
35
|
-
|
57
|
+
aat_int32 result = AAL2GetLibraryVersion(version, &version_len, bitness,
|
58
|
+
&bitness_len, type, &type_len);
|
36
59
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
return;
|
60
|
+
if (result != 0) {
|
61
|
+
vacman_library_error("AAL2GetLibraryVersion", result);
|
62
|
+
return Qnil;
|
41
63
|
}
|
42
64
|
|
43
|
-
VALUE
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
VALUE flag2 = rbhash_get_key(token, "flags2", T_FIXNUM);
|
48
|
-
|
49
|
-
memset(dpdata, 0, sizeof(*dpdata));
|
65
|
+
VALUE hash = rb_hash_new();
|
66
|
+
rb_hash_aset(hash, rb_str_new2("version"), rb_str_new2(version));
|
67
|
+
rb_hash_aset(hash, rb_str_new2("bitness"), rb_str_new2(bitness));
|
68
|
+
rb_hash_aset(hash, rb_str_new2("type"), rb_str_new2(type));
|
50
69
|
|
51
|
-
|
52
|
-
strncpy(dpdata->Serial, rb_string_value_cstr(&serial), sizeof(dpdata->Serial));
|
53
|
-
strncpy(dpdata->AppName, rb_string_value_cstr(&app_name), sizeof(dpdata->AppName));
|
54
|
-
dpdata->DPFlags[0] = rb_fix2int(flag1);
|
55
|
-
dpdata->DPFlags[1] = rb_fix2int(flag2);
|
70
|
+
return hash;
|
56
71
|
}
|
57
72
|
|
73
|
+
|
74
|
+
/*
|
75
|
+
* Convert a TDigipassBlob structure into a Ruby Hash
|
76
|
+
*/
|
58
77
|
static void digipass_to_rbhash(TDigipassBlob* dpdata, VALUE hash) {
|
59
78
|
char buffer[256];
|
60
79
|
|
@@ -74,39 +93,62 @@ static void digipass_to_rbhash(TDigipassBlob* dpdata, VALUE hash) {
|
|
74
93
|
rb_hash_aset(hash, rb_str_new2("flags2"), rb_fix_new(dpdata->DPFlags[1]));
|
75
94
|
}
|
76
95
|
|
96
|
+
|
77
97
|
/*
|
78
|
-
*
|
98
|
+
* Gets the given property from the given token hash and raises an Error
|
99
|
+
* if the following conditions occur:
|
100
|
+
*
|
101
|
+
* * The key is not found
|
102
|
+
* * The key is not of the given type
|
103
|
+
*
|
104
|
+
* Otherwise, the value corresponding to the key is returned.
|
105
|
+
*
|
79
106
|
*/
|
80
|
-
static VALUE
|
81
|
-
|
82
|
-
aat_int32 version_len = sizeof(version);
|
107
|
+
static VALUE rbhash_get_key(VALUE token, const char *property, int type) {
|
108
|
+
VALUE ret = rb_hash_aref(token, rb_str_new2(property));
|
83
109
|
|
84
|
-
|
85
|
-
|
110
|
+
if (ret == Qnil) {
|
111
|
+
rb_raise(e_VacmanError, "invalid token object given: %s property is nil", property);
|
112
|
+
return Qnil;
|
113
|
+
}
|
86
114
|
|
87
|
-
|
88
|
-
|
115
|
+
if (!RB_TYPE_P(ret, type)) {
|
116
|
+
rb_raise(e_VacmanError, "invalid token object given: %s property is not of the correct type", property);
|
117
|
+
return Qnil;
|
118
|
+
}
|
89
119
|
|
90
|
-
|
91
|
-
|
120
|
+
return ret;
|
121
|
+
}
|
92
122
|
|
93
|
-
|
94
|
-
|
95
|
-
|
123
|
+
|
124
|
+
/*
|
125
|
+
* Convert a Ruby Hash with the required keys to a TDigipassBlob structure.
|
126
|
+
*/
|
127
|
+
static void rbhash_to_digipass(VALUE token, TDigipassBlob* dpdata) {
|
128
|
+
if (!RB_TYPE_P(token, T_HASH)) {
|
129
|
+
rb_raise(e_VacmanError, "invalid token object given, requires an hash");
|
130
|
+
return;
|
96
131
|
}
|
97
132
|
|
98
|
-
VALUE
|
99
|
-
|
100
|
-
|
101
|
-
|
133
|
+
VALUE blob = rbhash_get_key(token, "blob", T_STRING);
|
134
|
+
VALUE serial = rbhash_get_key(token, "serial", T_STRING);
|
135
|
+
VALUE app_name = rbhash_get_key(token, "app_name", T_STRING);
|
136
|
+
VALUE flag1 = rbhash_get_key(token, "flags1", T_FIXNUM);
|
137
|
+
VALUE flag2 = rbhash_get_key(token, "flags2", T_FIXNUM);
|
102
138
|
|
103
|
-
|
139
|
+
memset(dpdata, 0, sizeof(*dpdata));
|
140
|
+
|
141
|
+
strcpy(dpdata->Blob, rb_string_value_cstr(&blob));
|
142
|
+
strncpy(dpdata->Serial, rb_string_value_cstr(&serial), sizeof(dpdata->Serial));
|
143
|
+
strncpy(dpdata->AppName, rb_string_value_cstr(&app_name), sizeof(dpdata->AppName));
|
144
|
+
dpdata->DPFlags[0] = rb_fix2int(flag1);
|
145
|
+
dpdata->DPFlags[1] = rb_fix2int(flag2);
|
104
146
|
}
|
105
147
|
|
106
148
|
|
149
|
+
|
107
150
|
/*
|
108
|
-
*
|
109
|
-
* this will not work with all the dpx files available, it must be prepared for it
|
151
|
+
* Generate an OTP from the given token, if the token allows it.
|
110
152
|
*/
|
111
153
|
static VALUE vacman_generate_password(VALUE module, VALUE token) {
|
112
154
|
TDigipassBlob dpdata;
|
@@ -116,11 +158,11 @@ static VALUE vacman_generate_password(VALUE module, VALUE token) {
|
|
116
158
|
aat_ascii password[18];
|
117
159
|
memset(password, 0, sizeof(password));
|
118
160
|
|
119
|
-
aat_int32 result = AAL2GenPassword(&dpdata, &
|
161
|
+
aat_int32 result = AAL2GenPassword(&dpdata, &g_KernelParms, password, NULL);
|
120
162
|
digipass_to_rbhash(&dpdata, token);
|
121
163
|
|
122
164
|
if (result != 0) {
|
123
|
-
|
165
|
+
vacman_library_error("AAL2GenPassword", result);
|
124
166
|
return Qnil;
|
125
167
|
}
|
126
168
|
|
@@ -129,7 +171,7 @@ static VALUE vacman_generate_password(VALUE module, VALUE token) {
|
|
129
171
|
|
130
172
|
|
131
173
|
/*
|
132
|
-
*
|
174
|
+
* Vacman properties names and IDs registry
|
133
175
|
*/
|
134
176
|
struct token_property {
|
135
177
|
const char *name;
|
@@ -192,10 +234,11 @@ static long vacman_get_property_id(char *property_name) {
|
|
192
234
|
}
|
193
235
|
}
|
194
236
|
|
195
|
-
rb_raise(
|
237
|
+
rb_raise(e_VacmanError, "Invalid property name `%s'", property_name);
|
196
238
|
return 0;
|
197
239
|
}
|
198
240
|
|
241
|
+
|
199
242
|
/*
|
200
243
|
* Get token property names
|
201
244
|
*/
|
@@ -212,7 +255,7 @@ static VALUE vacman_get_token_property_names(void) {
|
|
212
255
|
|
213
256
|
|
214
257
|
/*
|
215
|
-
* Get token
|
258
|
+
* Get the given property value from the given token.
|
216
259
|
*/
|
217
260
|
static VALUE vacman_get_token_property(VALUE module, VALUE token, VALUE property) {
|
218
261
|
TDigipassBlob dpdata;
|
@@ -220,19 +263,19 @@ static VALUE vacman_get_token_property(VALUE module, VALUE token, VALUE property
|
|
220
263
|
|
221
264
|
aat_ascii value[64];
|
222
265
|
aat_int32 property_id = vacman_get_property_id(StringValueCStr(property));
|
223
|
-
aat_int32 result = AAL2GetTokenProperty(&dpdata, &
|
266
|
+
aat_int32 result = AAL2GetTokenProperty(&dpdata, &g_KernelParms, property_id, value);
|
224
267
|
|
225
268
|
if (result == 0) {
|
226
269
|
return rb_str_new2(value);
|
227
270
|
} else {
|
228
|
-
|
271
|
+
vacman_library_error("AAL2GetTokenProperty", result);
|
229
272
|
return Qnil;
|
230
273
|
}
|
231
274
|
}
|
232
275
|
|
233
276
|
|
234
277
|
/*
|
235
|
-
* Set token
|
278
|
+
* Set the given token property to the given value.
|
236
279
|
*/
|
237
280
|
static VALUE vacman_set_token_property(VALUE module, VALUE token, VALUE property, VALUE rbval) {
|
238
281
|
TDigipassBlob dpdata;
|
@@ -242,75 +285,75 @@ static VALUE vacman_set_token_property(VALUE module, VALUE token, VALUE property
|
|
242
285
|
|
243
286
|
rbhash_to_digipass(token, &dpdata);
|
244
287
|
|
245
|
-
aat_int32 result = AAL2SetTokenProperty(&dpdata, &
|
288
|
+
aat_int32 result = AAL2SetTokenProperty(&dpdata, &g_KernelParms, property_id, value);
|
246
289
|
|
247
290
|
digipass_to_rbhash(&dpdata, token);
|
248
291
|
|
249
292
|
if (result == 0) {
|
250
293
|
return Qtrue;
|
251
294
|
} else {
|
252
|
-
|
295
|
+
vacman_library_error("AAL2SetTokenProperty", result);
|
253
296
|
return Qnil;
|
254
297
|
}
|
255
298
|
}
|
256
299
|
|
257
300
|
|
258
301
|
/*
|
259
|
-
*
|
302
|
+
* Changes the static password on the given token.
|
260
303
|
*/
|
261
304
|
static VALUE vacman_set_token_pin(VALUE module, VALUE token, VALUE pin) {
|
262
305
|
TDigipassBlob dpdata;
|
263
306
|
|
264
307
|
if (!RB_TYPE_P(pin, T_STRING)) {
|
265
|
-
rb_raise(
|
308
|
+
rb_raise(e_VacmanError, "invalid pin given, requires a string");
|
266
309
|
return Qnil;
|
267
310
|
}
|
268
311
|
|
269
312
|
rbhash_to_digipass(token, &dpdata);
|
270
313
|
|
271
314
|
aat_ascii *passwd = StringValueCStr(pin);
|
272
|
-
aat_int32 result = AAL2ChangeStaticPassword(&dpdata, &
|
315
|
+
aat_int32 result = AAL2ChangeStaticPassword(&dpdata, &g_KernelParms, passwd, passwd);
|
273
316
|
|
274
317
|
digipass_to_rbhash(&dpdata, token);
|
275
318
|
|
276
319
|
if (result == 0) {
|
277
320
|
return Qtrue;
|
278
321
|
} else {
|
279
|
-
|
322
|
+
vacman_library_error("AAL2ChangeStaticPassword", result);
|
280
323
|
return Qnil;
|
281
324
|
}
|
282
325
|
}
|
283
326
|
|
284
327
|
|
285
328
|
/*
|
286
|
-
*
|
287
|
-
* this is the main usecase, check the use input for authentication
|
329
|
+
* Verifies the given OTP against the given token.
|
288
330
|
*/
|
289
|
-
static VALUE vacman_verify_password(VALUE module, VALUE token, VALUE password
|
331
|
+
static VALUE vacman_verify_password(VALUE module, VALUE token, VALUE password) {
|
290
332
|
TDigipassBlob dpdata;
|
291
333
|
|
292
334
|
rbhash_to_digipass(token, &dpdata);
|
293
335
|
|
294
|
-
aat_int32 result = AAL2VerifyPassword(&dpdata, &
|
336
|
+
aat_int32 result = AAL2VerifyPassword(&dpdata, &g_KernelParms, rb_string_value_cstr(&password), 0);
|
295
337
|
|
296
338
|
digipass_to_rbhash(&dpdata, token);
|
297
339
|
|
298
340
|
if (result == 0)
|
299
341
|
return Qtrue;
|
300
342
|
else {
|
301
|
-
|
343
|
+
vacman_library_error("AAL2VerifyPassword", result);
|
302
344
|
return Qnil;
|
303
345
|
}
|
304
346
|
}
|
305
347
|
|
306
348
|
|
307
|
-
|
308
349
|
/*
|
309
|
-
*
|
350
|
+
* Imports a .DPX file containing token seeds and initialisation values.
|
351
|
+
*
|
352
|
+
* Pass the pre-shared key to validate it as the second argument. The
|
353
|
+
* key is not validated by the AAL2 library, if you pass a different
|
354
|
+
* key than the one that was used to create the DPX, you will get back
|
355
|
+
* tokens that generate different OTPs.
|
310
356
|
*
|
311
|
-
* Pass the pre-shared key to validate it as the second argument. Or if
|
312
|
-
* you don't have the key, replace the DC line with one from a file you
|
313
|
-
* know the key. Yes.
|
314
357
|
*/
|
315
358
|
static VALUE vacman_import(VALUE module, VALUE filename, VALUE key) {
|
316
359
|
TDPXHandle dpx_handle;
|
@@ -318,11 +361,15 @@ static VALUE vacman_import(VALUE module, VALUE filename, VALUE key) {
|
|
318
361
|
aat_ascii appl_names[13*8];
|
319
362
|
aat_int16 token_count;
|
320
363
|
|
321
|
-
aat_int32 result = AAL2DPXInit(&dpx_handle,
|
322
|
-
|
364
|
+
aat_int32 result = AAL2DPXInit(&dpx_handle,
|
365
|
+
rb_string_value_cstr(&filename),
|
366
|
+
rb_string_value_cstr(&key),
|
367
|
+
&appl_count,
|
368
|
+
appl_names,
|
369
|
+
&token_count);
|
323
370
|
|
324
371
|
if (result != 0) {
|
325
|
-
|
372
|
+
vacman_library_error("AAL2DPXInit", result);
|
326
373
|
return Qnil;
|
327
374
|
}
|
328
375
|
|
@@ -335,7 +382,7 @@ static VALUE vacman_import(VALUE module, VALUE filename, VALUE key) {
|
|
335
382
|
|
336
383
|
while (1) {
|
337
384
|
result = AAL2DPXGetToken(&dpx_handle,
|
338
|
-
&
|
385
|
+
&g_KernelParms,
|
339
386
|
appl_names,
|
340
387
|
sw_out_serial_No,
|
341
388
|
sw_out_type,
|
@@ -344,9 +391,10 @@ static VALUE vacman_import(VALUE module, VALUE filename, VALUE key) {
|
|
344
391
|
|
345
392
|
|
346
393
|
if (result < 0) {
|
347
|
-
|
394
|
+
vacman_library_error("AAL2DPXGetToken", result);
|
348
395
|
return Qnil;
|
349
396
|
}
|
397
|
+
|
350
398
|
if (result == 107) break;
|
351
399
|
|
352
400
|
VALUE hash = rb_hash_new();
|
@@ -361,30 +409,48 @@ static VALUE vacman_import(VALUE module, VALUE filename, VALUE key) {
|
|
361
409
|
return list;
|
362
410
|
}
|
363
411
|
|
412
|
+
|
413
|
+
/*
|
414
|
+
* Vacman Controller kernel properties
|
415
|
+
*/
|
364
416
|
struct kernel_property {
|
365
417
|
const char *name;
|
366
418
|
aat_int32 *value;
|
367
419
|
aat_int32 deflt;
|
368
420
|
};
|
369
421
|
static struct kernel_property kernel_properties[] = {
|
370
|
-
{ "ITimeWindow", &
|
371
|
-
{ "STimeWindow", &
|
372
|
-
{ "DiagLevel", &
|
373
|
-
{ "GMTAdjust", &
|
374
|
-
{ "CheckChallenge", &
|
375
|
-
{ "IThreshold", &
|
376
|
-
{ "SThreshold", &
|
377
|
-
{ "ChkInactDays", &
|
378
|
-
{ "DeriveVector", &
|
379
|
-
{ "SyncWindow", &
|
380
|
-
{ "OnLineSG", &
|
381
|
-
{ "EventWindow", &
|
382
|
-
{ "HSMSlotId", &
|
422
|
+
{ "ITimeWindow", &g_KernelParms.ITimeWindow, 30 }, // Identification Window size in time steps
|
423
|
+
{ "STimeWindow", &g_KernelParms.STimeWindow, 24 }, // Signature Window size in secs
|
424
|
+
{ "DiagLevel", &g_KernelParms.DiagLevel, 0 }, // Requested Diagnostic Level
|
425
|
+
{ "GMTAdjust", &g_KernelParms.GMTAdjust, 0 }, // GMT Time adjustment to perform
|
426
|
+
{ "CheckChallenge", &g_KernelParms.CheckChallenge, 0 }, // Verify Challenge Corrupted (mandatory for Gordian)
|
427
|
+
{ "IThreshold", &g_KernelParms.IThreshold, 3 }, // Identification Error Threshold
|
428
|
+
{ "SThreshold", &g_KernelParms.SThreshold, 1 }, // Signature Error Threshold
|
429
|
+
{ "ChkInactDays", &g_KernelParms.ChkInactDays, 0 }, // Check Inactive Days
|
430
|
+
{ "DeriveVector", &g_KernelParms.DeriveVector, 0 }, // Vector used to make Data Encryption unique
|
431
|
+
{ "SyncWindow", &g_KernelParms.SyncWindow, 2 }, // Synchronisation Time Window (h)
|
432
|
+
{ "OnLineSG", &g_KernelParms.OnLineSG, 2 }, // On line signature
|
433
|
+
{ "EventWindow", &g_KernelParms.EventWindow, 100 }, // Event Window size in nbr of iterations
|
434
|
+
{ "HSMSlotId", &g_KernelParms.HSMSlotId, 0 }, // HSM Slot id uses to store DB and Transport Key
|
383
435
|
};
|
384
436
|
static size_t kernel_properties_count = sizeof(kernel_properties)/sizeof(struct kernel_property);
|
385
437
|
|
386
438
|
/*
|
387
|
-
*
|
439
|
+
* Initialise the kernel parameters with their defaults
|
440
|
+
*/
|
441
|
+
static void vacman_init_kernel_params() {
|
442
|
+
memset(&g_KernelParms, 0, sizeof(g_KernelParms));
|
443
|
+
|
444
|
+
g_KernelParms.ParmCount = 19; /* Number of valid parameters in this list */
|
445
|
+
|
446
|
+
for (size_t i = 0; i < kernel_properties_count; i++) {
|
447
|
+
*kernel_properties[i].value = kernel_properties[i].deflt;
|
448
|
+
}
|
449
|
+
}
|
450
|
+
|
451
|
+
|
452
|
+
/*
|
453
|
+
* Get kernel parameter names
|
388
454
|
*/
|
389
455
|
static VALUE vacman_get_kernel_property_names(void) {
|
390
456
|
VALUE ret = rb_ary_new();
|
@@ -397,6 +463,7 @@ static VALUE vacman_get_kernel_property_names(void) {
|
|
397
463
|
return ret;
|
398
464
|
}
|
399
465
|
|
466
|
+
|
400
467
|
/*
|
401
468
|
* Set kernel parameter
|
402
469
|
*/
|
@@ -411,7 +478,7 @@ static VALUE vacman_set_kernel_param(VALUE module, VALUE paramname, VALUE rbval)
|
|
411
478
|
}
|
412
479
|
}
|
413
480
|
|
414
|
-
rb_raise(
|
481
|
+
rb_raise(e_VacmanError, "Invalid kernel param %s", name);
|
415
482
|
return Qnil;
|
416
483
|
}
|
417
484
|
|
@@ -428,48 +495,36 @@ static VALUE vacman_get_kernel_param(VALUE module, VALUE paramname) {
|
|
428
495
|
}
|
429
496
|
}
|
430
497
|
|
431
|
-
rb_raise(
|
498
|
+
rb_raise(e_VacmanError, "Invalid kernel param %s", name);
|
432
499
|
return Qnil;
|
433
500
|
}
|
434
501
|
|
435
|
-
/*
|
436
|
-
* Init the kernel parameters, with their defaults
|
437
|
-
*/
|
438
|
-
static void init_kernel_params() {
|
439
|
-
memset(&KernelParms, 0, sizeof(TKernelParms));
|
440
|
-
|
441
|
-
KernelParms.ParmCount = 19; /* Number of valid parameters in this list */
|
442
|
-
|
443
|
-
for (size_t i = 0; i < kernel_properties_count; i++) {
|
444
|
-
*kernel_properties[i].value = kernel_properties[i].deflt;
|
445
|
-
}
|
446
|
-
}
|
447
|
-
|
448
502
|
|
449
503
|
/*
|
450
|
-
*
|
504
|
+
* Extension entry point
|
451
505
|
*/
|
452
|
-
void
|
453
|
-
VALUE
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
rb_define_singleton_method(
|
463
|
-
|
464
|
-
|
465
|
-
rb_define_singleton_method(
|
466
|
-
rb_define_singleton_method(
|
467
|
-
|
468
|
-
rb_define_singleton_method(
|
469
|
-
rb_define_singleton_method(
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
rb_define_singleton_method(
|
474
|
-
rb_define_singleton_method(
|
506
|
+
void Init_low_level(void) {
|
507
|
+
VALUE controller = rb_define_module("VacmanController");
|
508
|
+
VALUE lowlevel = rb_define_module_under(controller, "LowLevel");
|
509
|
+
|
510
|
+
e_VacmanError = rb_define_class_under(controller, "Error", rb_eStandardError);
|
511
|
+
|
512
|
+
vacman_init_kernel_params();
|
513
|
+
|
514
|
+
/* Global methods */
|
515
|
+
rb_define_singleton_method(lowlevel, "library_version", vacman_library_version, 0);
|
516
|
+
rb_define_singleton_method(lowlevel, "import", vacman_import, 2);
|
517
|
+
|
518
|
+
/* Token methods */
|
519
|
+
rb_define_singleton_method(lowlevel, "token_property_names", vacman_get_token_property_names, 0);
|
520
|
+
rb_define_singleton_method(lowlevel, "get_token_property", vacman_get_token_property, 2);
|
521
|
+
rb_define_singleton_method(lowlevel, "set_token_property", vacman_set_token_property, 3);
|
522
|
+
rb_define_singleton_method(lowlevel, "generate_password", vacman_generate_password, 1);
|
523
|
+
rb_define_singleton_method(lowlevel, "verify_password", vacman_verify_password, 2);
|
524
|
+
rb_define_singleton_method(lowlevel, "set_token_pin", vacman_set_token_pin, 2);
|
525
|
+
|
526
|
+
/* Kernel methods */
|
527
|
+
rb_define_singleton_method(lowlevel, "kernel_property_names", vacman_get_kernel_property_names, 0);
|
528
|
+
rb_define_singleton_method(lowlevel, "get_kernel_param", vacman_get_kernel_param, 1);
|
529
|
+
rb_define_singleton_method(lowlevel, "set_kernel_param", vacman_set_kernel_param, 2);
|
475
530
|
}
|
data/lib/vacman_controller.rb
CHANGED
@@ -1,176 +1,60 @@
|
|
1
|
-
require 'vacman_controller/
|
1
|
+
require 'vacman_controller/low_level'
|
2
|
+
require 'vacman_controller/token'
|
3
|
+
require 'vacman_controller/kernel'
|
4
|
+
require 'vacman_controller/error'
|
2
5
|
|
3
|
-
#
|
4
|
-
#
|
6
|
+
# Wraps VACMAN Controller functionality for Ruby.
|
5
7
|
#
|
6
8
|
module VacmanController
|
7
|
-
extend self
|
8
|
-
|
9
|
-
# Import .dpx file containing the secure token-data
|
10
|
-
#
|
11
|
-
# == Parameters:
|
12
|
-
# filename::
|
13
|
-
# The path of the .dpx file to load
|
14
|
-
# key::
|
15
|
-
# The secure key to decrypt the dpx file
|
16
|
-
#
|
17
|
-
# == Returns:
|
18
|
-
# A list of hashes. Each hash contains
|
19
|
-
# serial: the serial number of the token
|
20
|
-
# blob: the blob containing some secret magic data
|
21
|
-
# app_name: the application name (the security method)
|
22
|
-
# flags1: some flags
|
23
|
-
# flags2: more flags
|
24
|
-
#
|
25
|
-
# this hash must be persisted and regained for each call of verify_password and generate_password
|
26
|
-
#
|
27
|
-
def import(filename, key)
|
28
|
-
VacmanLowLevel.import(filename, key)
|
29
|
-
end
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
# Generate a Password for a user. This does the same as hitting the button on your hardware token
|
34
|
-
#
|
35
|
-
# == Parameters:
|
36
|
-
# hash::
|
37
|
-
# The hash for a specific token (you get these in import)
|
38
|
-
#
|
39
|
-
# == Returns:
|
40
|
-
# The password string. The password is only valid for a period (todo: add method to change the period, currently its 30 seconds)
|
41
|
-
#
|
42
|
-
def generate_password(hash)
|
43
|
-
VacmanLowLevel.generate_password(hash)
|
44
|
-
end
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
# Verify a password. This is the usecase a user sends you a password generated by his token and we have to verify it.
|
49
|
-
#
|
50
|
-
# == Parameters:
|
51
|
-
# hash::
|
52
|
-
# The hash for a specific token (you get these in import)
|
53
|
-
# pw::
|
54
|
-
# The password provided by the user
|
55
|
-
#
|
56
|
-
# == Returns:
|
57
|
-
# true if the password is valid, false otherwise
|
58
|
-
#
|
59
|
-
# ATTENTION: it is very important to persist the hash afterwards!!!
|
60
|
-
#
|
61
|
-
def verify_password(hash, pw)
|
62
|
-
VacmanLowLevel.verify_password(hash, pw)
|
63
|
-
end
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
# Gets the available kernel property names
|
68
|
-
#
|
69
|
-
def kernel_property_names
|
70
|
-
@_kernel_property_names ||= VacmanLowLevel.kernel_property_names
|
71
|
-
end
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
# Get a kernel parameter, wich is a basically a setting for vacman controller
|
76
|
-
#
|
77
|
-
# == Parameters:
|
78
|
-
# name::
|
79
|
-
# the param name. Most TKernelParms struct elements are accessible.
|
80
|
-
#
|
81
|
-
def get_kernel_param(name)
|
82
|
-
VacmanLowLevel.get_kernel_param(name)
|
83
|
-
end
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
# Change a kernel parameter, wich is a basically a setting for vacman controller
|
88
|
-
#
|
89
|
-
# == Parameters:
|
90
|
-
# name::
|
91
|
-
# the param name. Most TKernelParms struct elements are accessible.
|
92
|
-
# val::
|
93
|
-
# the fixnum value
|
94
|
-
#
|
95
|
-
def set_kernel_param(name, val)
|
96
|
-
VacmanLowLevel.set_kernel_param(name, val)
|
97
|
-
end
|
98
9
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
10
|
+
VERSION = '0.5.0'
|
11
|
+
|
12
|
+
class << self
|
13
|
+
# Imports a .dpx file containing the token key material.
|
14
|
+
#
|
15
|
+
# == Parameters:
|
16
|
+
#
|
17
|
+
# filename::
|
18
|
+
# The path of the .dpx file to load
|
19
|
+
#
|
20
|
+
# key::
|
21
|
+
# The transport key to decrypt the dpx file
|
22
|
+
#
|
23
|
+
# == Returns:
|
24
|
+
# An Array of Ruby Hashes. Each Hash contains the following keys:
|
25
|
+
#
|
26
|
+
# serial: the serial number of the token
|
27
|
+
# blob: the blob containing some secret magic data
|
28
|
+
# app_name: the application name (the security method)
|
29
|
+
# flags1: flags
|
30
|
+
# flags2: flags
|
31
|
+
#
|
32
|
+
# This is only for low-level usage. For a Ruby API, look at
|
33
|
+
# +VacmanController::Token.import+.
|
34
|
+
#
|
35
|
+
def import(filename, key)
|
36
|
+
VacmanController::LowLevel.import(filename, key)
|
37
|
+
|
38
|
+
rescue VacmanController::Error => e
|
39
|
+
# We handle two undocumented error codes here
|
40
|
+
case e.error_code
|
41
|
+
when -15
|
42
|
+
raise VacmanController::Error, "#{e.library_method} error #{e.error_code}: invalid transport key"
|
43
|
+
|
44
|
+
when -20
|
45
|
+
raise VacmanController::Error, "#{e.library_method} error #{e.error_code}: cannot open DPX file"
|
46
|
+
|
47
|
+
else
|
48
|
+
raise # Sorry, I did my best.
|
49
|
+
|
50
|
+
end
|
106
51
|
end
|
107
|
-
end
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
# Gets the available token property names
|
112
|
-
#
|
113
|
-
def token_property_names
|
114
|
-
@_token_property_names ||= VacmanLowLevel.token_property_names
|
115
|
-
end
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
# Get a token single property
|
120
|
-
#
|
121
|
-
# == Parameters:
|
122
|
-
# hash::
|
123
|
-
# the hash for a specific token (you get these in import)
|
124
|
-
# property::
|
125
|
-
# the property name. See +token_property_names+
|
126
|
-
#
|
127
|
-
def get_token_property(hash, property)
|
128
|
-
VacmanLowLevel.get_token_property(hash, property)
|
129
|
-
end
|
130
52
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
# == Parameters:
|
136
|
-
# hash::
|
137
|
-
# the hash for a specific token (you get these in import)
|
138
|
-
# property::
|
139
|
-
# the property name. See +token_property_names+
|
140
|
-
# value::
|
141
|
-
# the property value. Only values convertible to integer are supported.
|
142
|
-
#
|
143
|
-
# possible names:
|
144
|
-
#
|
145
|
-
#
|
146
|
-
def set_token_property(hash, property, value)
|
147
|
-
VacmanLowLevel.set_token_property(hash, property, value)
|
148
|
-
end
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
# Set a token PIN
|
153
|
-
#
|
154
|
-
# == Parameters:
|
155
|
-
# hash::
|
156
|
-
# the hash for a specific token (you get these in import)
|
157
|
-
# pin::
|
158
|
-
# the new PIN. must be a string.
|
159
|
-
#
|
160
|
-
# possible names:
|
161
|
-
#
|
162
|
-
#
|
163
|
-
def set_token_pin(hash, pin)
|
164
|
-
VacmanLowLevel.set_token_pin(hash, pin)
|
165
|
-
end
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
# Returns all properties configured for a token
|
170
|
-
#
|
171
|
-
def get_token_all_properties(hash)
|
172
|
-
token_property_names.inject({}) do |h, name|
|
173
|
-
h.update(name => (get_token_property(hash, name) rescue "ERROR: #$!"))
|
53
|
+
# Returns the +Kernel+ module
|
54
|
+
#
|
55
|
+
def kernel
|
56
|
+
VacmanController::Kernel
|
174
57
|
end
|
175
58
|
end
|
59
|
+
|
176
60
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module VacmanController
|
2
|
+
|
3
|
+
# Represents a Vacman Controller Library error.
|
4
|
+
#
|
5
|
+
class Error < StandardError
|
6
|
+
# The AAL2 library method that errored
|
7
|
+
attr_reader :library_method
|
8
|
+
|
9
|
+
# The error code returned by the AAL2 library
|
10
|
+
attr_reader :error_code
|
11
|
+
|
12
|
+
# The error message retrieved by the AAL2 library
|
13
|
+
attr_reader :error_message
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module VacmanController
|
2
|
+
|
3
|
+
module Kernel
|
4
|
+
class << self
|
5
|
+
# Returns the library version as an hash
|
6
|
+
#
|
7
|
+
def version
|
8
|
+
@_version = VacmanController::LowLevel.library_version
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
# Gets the available kernel property names
|
13
|
+
#
|
14
|
+
def property_names
|
15
|
+
@_property_names ||= VacmanController::LowLevel.kernel_property_names.freeze
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
# Shows the kernel version, bitness, type and parameters in your
|
20
|
+
# development console.
|
21
|
+
#
|
22
|
+
def inspect
|
23
|
+
"#<#{self.name} version=#{version['version'].inspect} bitness=#{version['bitness'].inspect} "\
|
24
|
+
"type=#{version['type'].inspect} parameters=#{all.inspect}>>"
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
# Returns all configured parameters
|
29
|
+
#
|
30
|
+
def all
|
31
|
+
property_names.inject({}) do |h, name|
|
32
|
+
h.update(name => (self[name] rescue "ERROR: #$!"))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
alias to_h all
|
36
|
+
|
37
|
+
|
38
|
+
# Get a Kernel property, that is a runtime parameter of Vacman Controller,
|
39
|
+
# stored in the TKernelParms structure.
|
40
|
+
#
|
41
|
+
# == Parameters:
|
42
|
+
# name::
|
43
|
+
# The param name. See +property_names+ for a list of available property
|
44
|
+
# names.
|
45
|
+
#
|
46
|
+
def [](name)
|
47
|
+
VacmanController::LowLevel.get_kernel_param(name)
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
# Set a Kernel property.
|
52
|
+
#
|
53
|
+
# == Parameters:
|
54
|
+
# name::
|
55
|
+
# the param name. See +property_names+ for a list of available property
|
56
|
+
# names. The Kernel parameters are all int32 properties.
|
57
|
+
#
|
58
|
+
# val::
|
59
|
+
# the integer value
|
60
|
+
#
|
61
|
+
def []=(name, val)
|
62
|
+
Mutex.synchronize do
|
63
|
+
VacmanController::LowLevel.set_kernel_param(name, val)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
Mutex = Thread::Mutex.new
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
require 'vacman_controller/token/properties'
|
2
|
+
|
3
|
+
module VacmanController
|
4
|
+
|
5
|
+
class Token
|
6
|
+
# Opens the given dpx_filename with the given transport key and,
|
7
|
+
# if successful, returns Token instances for all tokens in the
|
8
|
+
# DPX file.
|
9
|
+
#
|
10
|
+
def self.import(dpx_filename, transport_key)
|
11
|
+
VacmanController.import(dpx_filename, transport_key).map do |hash|
|
12
|
+
Token.new(hash)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
# Initialises a Token instance with the given token hash.
|
18
|
+
#
|
19
|
+
def initialize(token_hash)
|
20
|
+
@token_hash = token_hash
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
# Return the token serial number
|
25
|
+
#
|
26
|
+
def serial
|
27
|
+
@token_hash.fetch('serial').dup
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
# Returns the token Application Name
|
32
|
+
#
|
33
|
+
def app_name
|
34
|
+
@token_hash.fetch('app_name').dup
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
# Renders this token in your development console
|
39
|
+
# and in your logs (possibly)
|
40
|
+
#
|
41
|
+
def inspect
|
42
|
+
"#<#{self.class.name} serial=#{serial.inspect} app_name=#{app_name.inspect}>"
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
# Returns the token as an hash, that is suitable for passing to
|
47
|
+
# the low-level functions, or for persistance purposes.
|
48
|
+
#
|
49
|
+
def to_h
|
50
|
+
@token_hash
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
# Verify a password. This is the usecase a user sends you an OTP
|
55
|
+
# generated by their token and we have to verify it.
|
56
|
+
#
|
57
|
+
# == Parameters:
|
58
|
+
# otp::
|
59
|
+
# The OTP provided by the user
|
60
|
+
#
|
61
|
+
# == Returns:
|
62
|
+
# true if the password is valid, false otherwise
|
63
|
+
#
|
64
|
+
# ATTENTION: it is very important to persist the token hash
|
65
|
+
# afterwards.
|
66
|
+
#
|
67
|
+
def verify(otp)
|
68
|
+
verify!(otp)
|
69
|
+
rescue VacmanController::Error
|
70
|
+
false
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
# Same as verify, but raises a VacmanController::Error if OTP verification
|
75
|
+
# fails.
|
76
|
+
#
|
77
|
+
def verify!(otp)
|
78
|
+
VacmanController::LowLevel.verify_password(@token_hash, otp.to_s)
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
# Generate an OTPfrom this token. This does the same as hitting the button
|
83
|
+
# on the hardware token.
|
84
|
+
#
|
85
|
+
# == Returns:
|
86
|
+
# The OTP as a String. The OTP is only valid for a limited time period.
|
87
|
+
#
|
88
|
+
# Not all tokens support OTP generation.
|
89
|
+
#
|
90
|
+
def generate
|
91
|
+
VacmanController::LowLevel.generate_password(@token_hash)
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
# Set this token's PIN
|
96
|
+
#
|
97
|
+
# == Parameters:
|
98
|
+
# pin::
|
99
|
+
# the new PIN. Must be coercible to String.
|
100
|
+
#
|
101
|
+
def set_pin(pin)
|
102
|
+
VacmanController::LowLevel.set_token_pin(@token_hash, pin.to_s)
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
####################################################################
|
107
|
+
##### Properties Management
|
108
|
+
####################################################################
|
109
|
+
|
110
|
+
# Enables the PIN on this token
|
111
|
+
#
|
112
|
+
def enable_pin!
|
113
|
+
properties[:pin_enabled] = 1
|
114
|
+
true
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
# Disables the PIN on this token
|
119
|
+
#
|
120
|
+
def disable_pin!
|
121
|
+
properties[:pin_enabled] = 2
|
122
|
+
true
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
# Forces PIN change on this token
|
127
|
+
#
|
128
|
+
def force_pin_change!
|
129
|
+
properties[:pin_change_forced] = 1
|
130
|
+
true
|
131
|
+
end
|
132
|
+
|
133
|
+
|
134
|
+
# Resets the token error count
|
135
|
+
#
|
136
|
+
def reset_error_count!
|
137
|
+
properties[:error_count] = 0
|
138
|
+
true
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
# Sets the "disabled" token status
|
143
|
+
#
|
144
|
+
def disable!
|
145
|
+
properties[:token_status] = 0
|
146
|
+
true
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
# Set the primary application enabled status
|
151
|
+
#
|
152
|
+
def enable_primary_only!
|
153
|
+
properties[:token_status] = 1
|
154
|
+
true
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
# Set the backup application enabled status
|
159
|
+
#
|
160
|
+
def enable_backup_only!
|
161
|
+
properties[:token_status] = 2
|
162
|
+
true
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
# Set both primary and backup application enabled status
|
167
|
+
#
|
168
|
+
def enable!
|
169
|
+
properties[:token_status] = 3
|
170
|
+
true
|
171
|
+
end
|
172
|
+
|
173
|
+
|
174
|
+
# Returns a +Token::Properties+ object giving low-level access to the
|
175
|
+
# token properties.
|
176
|
+
#
|
177
|
+
def properties
|
178
|
+
@_properties = VacmanController::Token::Properties.new(self)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
@@ -0,0 +1,193 @@
|
|
1
|
+
module VacmanController
|
2
|
+
class Token
|
3
|
+
|
4
|
+
class Properties
|
5
|
+
class << self
|
6
|
+
# Gets the available token property names
|
7
|
+
#
|
8
|
+
def names
|
9
|
+
@_names ||= VacmanController::LowLevel.token_property_names.freeze
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
def initialize(token)
|
15
|
+
@token = token
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def inspect
|
20
|
+
all.inspect
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
def all
|
25
|
+
self.class.names.inject({}) do |h, name|
|
26
|
+
h.update(name => (self[name] rescue "ERROR: #$!"))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
alias to_h all
|
30
|
+
|
31
|
+
|
32
|
+
# Get a Token property
|
33
|
+
#
|
34
|
+
# == Parameters:
|
35
|
+
#
|
36
|
+
# property::
|
37
|
+
# the property name. See +Token::Properties.names+
|
38
|
+
#
|
39
|
+
def [](name)
|
40
|
+
name = name.to_s
|
41
|
+
value = VacmanController::LowLevel.get_token_property(@token.to_h, name)
|
42
|
+
|
43
|
+
cast(name, value)
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
# Set a Token property
|
48
|
+
#
|
49
|
+
# == Parameters:
|
50
|
+
#
|
51
|
+
# property::
|
52
|
+
# the property name. See +Token.property_names+
|
53
|
+
#
|
54
|
+
# value::
|
55
|
+
# the property value. Only values convertible to integer are
|
56
|
+
# supported.
|
57
|
+
#
|
58
|
+
def []=(name, value)
|
59
|
+
name = name.to_s
|
60
|
+
value = value.to_i
|
61
|
+
|
62
|
+
check_bounded_property!(name, value)
|
63
|
+
|
64
|
+
VacmanController::LowLevel.set_token_property(@token.to_h, name, value)
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
protected
|
69
|
+
def bounded_property?(name)
|
70
|
+
PROPERTY_BOUNDS.key?(name)
|
71
|
+
end
|
72
|
+
|
73
|
+
# The library also does these checks, but we want to present
|
74
|
+
# custom error message to the caller.
|
75
|
+
#
|
76
|
+
def check_bounded_property!(name, value)
|
77
|
+
return unless bounded_property?(name)
|
78
|
+
|
79
|
+
min, max = PROPERTY_BOUNDS.fetch(name)
|
80
|
+
|
81
|
+
if value < min || value > max
|
82
|
+
raise VacmanController::Error,
|
83
|
+
"Invalid #{name} value provided: #{value}. " \
|
84
|
+
"Must be between greater than #{min} and less than #{max}."
|
85
|
+
end
|
86
|
+
|
87
|
+
true
|
88
|
+
end
|
89
|
+
|
90
|
+
PROPERTY_BOUNDS = {
|
91
|
+
'last_time_used' => [ 631152000, 2147483647 ],
|
92
|
+
|
93
|
+
'last_time_shift' => [ -100_000, 100_000 ],
|
94
|
+
|
95
|
+
'pin_min_length' => [ 3, 8 ],
|
96
|
+
'pin_minimum_length' => [ 3, 8 ],
|
97
|
+
|
98
|
+
'virtual_token_grace_period' => [ 1, 364 ],
|
99
|
+
|
100
|
+
'virtual_token_remain_use' => [ 0, 254 ],
|
101
|
+
|
102
|
+
'event_value' => [ 0, 4_294_967_294 ],
|
103
|
+
}
|
104
|
+
|
105
|
+
def cast(property, value)
|
106
|
+
|
107
|
+
# Short-circuit on 'NA'
|
108
|
+
return nil if value == 'NA' or value == 'DISABLE'
|
109
|
+
|
110
|
+
case property
|
111
|
+
when # Integer values
|
112
|
+
'use_count',
|
113
|
+
'pin_len',
|
114
|
+
'pin_length',
|
115
|
+
'pin_min_len',
|
116
|
+
'pin_minimum_length',
|
117
|
+
'last_time_shift',
|
118
|
+
'virtual_token_remain_use',
|
119
|
+
'error_count',
|
120
|
+
'event_value',
|
121
|
+
'last_event_value',
|
122
|
+
'max_dtf_number',
|
123
|
+
'response_len',
|
124
|
+
'response_length',
|
125
|
+
'time_step'
|
126
|
+
|
127
|
+
value.to_i
|
128
|
+
|
129
|
+
when # Boolean values
|
130
|
+
'time_based_algo',
|
131
|
+
'event_based_algo',
|
132
|
+
'pin_supported',
|
133
|
+
'unlock_supported',
|
134
|
+
'pin_ch_on',
|
135
|
+
'pin_change_enabled',
|
136
|
+
'pin_enabled',
|
137
|
+
'pin_ch_forced',
|
138
|
+
'pin_change_forced',
|
139
|
+
'sync_windows',
|
140
|
+
'primary_token_enabled',
|
141
|
+
'virtual_token_supported',
|
142
|
+
'virtual_token_enabled',
|
143
|
+
'derivation_supported',
|
144
|
+
'response_chk',
|
145
|
+
'response_checksum',
|
146
|
+
'triple_des_used',
|
147
|
+
'use_3des'
|
148
|
+
|
149
|
+
case value
|
150
|
+
when 'YES' then true
|
151
|
+
when 'NO' then false
|
152
|
+
end
|
153
|
+
|
154
|
+
when # Date/time values
|
155
|
+
'last_time_used',
|
156
|
+
'virtual_token_grace_period'
|
157
|
+
|
158
|
+
# AAL2 returns UTC values, we add the timezone.
|
159
|
+
Time.strptime("#{value} UTC", '%a %b %d %H:%M:%S %Y %Z')
|
160
|
+
|
161
|
+
when
|
162
|
+
'auth_mode'
|
163
|
+
|
164
|
+
case value
|
165
|
+
when 'RO' then :response_only
|
166
|
+
when 'SG' then :signature_application
|
167
|
+
when 'CR' then :challenge_response
|
168
|
+
when 'MM' then :multi_mode
|
169
|
+
when 'UL' then :unlock_v2
|
170
|
+
else
|
171
|
+
value
|
172
|
+
end
|
173
|
+
|
174
|
+
else # String values
|
175
|
+
|
176
|
+
value
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
private
|
181
|
+
def method_missing(name, *args, &block)
|
182
|
+
prop, setter = name.to_s.match(/\A(.+?)(=)?\Z/).values_at(1, 2)
|
183
|
+
|
184
|
+
if setter
|
185
|
+
self[prop] = args.first
|
186
|
+
else
|
187
|
+
self[prop]
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vacman_controller
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marcus Lankenau
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2019-
|
12
|
+
date: 2019-04-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake-compiler
|
@@ -25,7 +25,36 @@ dependencies:
|
|
25
25
|
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '0'
|
28
|
-
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rspec
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: guard-rspec
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
description: Expose the AAL2 SDK API via a set of Ruby classes optimised for developer
|
57
|
+
happiness
|
29
58
|
email:
|
30
59
|
- marcus.lankenau@gmail.com
|
31
60
|
- marcello.barnaba@gmail.com
|
@@ -35,9 +64,13 @@ extensions:
|
|
35
64
|
extra_rdoc_files: []
|
36
65
|
files:
|
37
66
|
- ext/vacman_controller/extconf.rb
|
38
|
-
- ext/vacman_controller/
|
67
|
+
- ext/vacman_controller/low_level.c
|
39
68
|
- lib/vacman_controller.rb
|
40
|
-
|
69
|
+
- lib/vacman_controller/error.rb
|
70
|
+
- lib/vacman_controller/kernel.rb
|
71
|
+
- lib/vacman_controller/token.rb
|
72
|
+
- lib/vacman_controller/token/properties.rb
|
73
|
+
homepage: https://github.com/ifad/vacman_controller
|
41
74
|
licenses: []
|
42
75
|
metadata: {}
|
43
76
|
post_install_message:
|
@@ -56,8 +89,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
56
89
|
version: '0'
|
57
90
|
requirements: []
|
58
91
|
rubyforge_project:
|
59
|
-
rubygems_version: 2.
|
92
|
+
rubygems_version: 2.7.6
|
60
93
|
signing_key:
|
61
94
|
specification_version: 4
|
62
|
-
summary:
|
95
|
+
summary: Ruby layer to access VASCO Vacman Controller functions
|
63
96
|
test_files: []
|