vacman_controller 0.2.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|