vacman_controller 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a82c1e1da792a6d845ed3fa39e2ad0a7f24dc022
4
+ data.tar.gz: df608d69585f838e1d1591fc2c4ba1c6496e61ed
5
+ SHA512:
6
+ metadata.gz: f6348405cfdec6d7cdb5450625d9b8bdb5f08c034f0a93d7f27884f03f91560152b8e16d92195abfb157f896ce654dc3fef6463ff0e0d77184552cc206c20e29
7
+ data.tar.gz: 3a023343b469676f06956f1e14ec7dfc63301e397ea66ac50e827199dd97b293b65e73640607ef23ea51cb9c1350b88c2eb244f6bb4e0246e21287d816f7460b
@@ -0,0 +1,24 @@
1
+ require 'mkmf'
2
+
3
+ def find_vacman_controller
4
+ Dir.glob('/opt/vasco/VACMAN_Controller-*').sort.reverse.first
5
+ end
6
+
7
+ VACMAN_CONTROLLER = ENV['VACMAN_PATH'] || find_vacman_controller
8
+
9
+ if VACMAN_CONTROLLER
10
+ puts "Using VACMAN controller from #{VACMAN_CONTROLLER}"
11
+ else
12
+ puts "No VASCO Vacman controller found in /opt/vasco"
13
+ exit 1
14
+ end
15
+
16
+ append_cflags "-I#{VACMAN_CONTROLLER}/include -Wall"
17
+ append_ldflags "-L#{VACMAN_CONTROLLER}/lib -laal2sdk -Wl,-rpath #{VACMAN_CONTROLLER}/lib"
18
+
19
+ if find_library('aal2sdk', 'AAL2DPXInit', "#{VACMAN_CONTROLLER}/lib")
20
+ create_makefile('vacman_controller/vacman_controller')
21
+ else
22
+ puts "No libaal2sdk found"
23
+ exit 1
24
+ end
@@ -0,0 +1,394 @@
1
+ #include <ruby.h>
2
+ #include <string.h>
3
+ #include <aal2sdk.h>
4
+
5
+ static VALUE e_vacmanerror; // our ruby exception type
6
+ TKernelParms KernelParms; // Kernel Params
7
+
8
+ /*
9
+ * raise an error and tell wich method failed with wich error code
10
+ */
11
+ static void vacman_raise_error(char* method, int error_code) {
12
+ aat_ascii error_message[100];
13
+ AAL2GetErrorMsg (error_code, error_message);
14
+ rb_raise(e_vacmanerror, "%s error %d: %s", method, error_code, error_message);
15
+ }
16
+
17
+
18
+ /*
19
+ * convert a ruby hash to TDigipassBlob structure
20
+ */
21
+ static void rbhash_to_digipass(VALUE token, TDigipassBlob* dpdata) {
22
+ memset(dpdata, 0, sizeof(*dpdata));
23
+
24
+ VALUE blob = rb_hash_aref(token, rb_str_new2("blob"));
25
+ VALUE serial = rb_hash_aref(token, rb_str_new2("serial"));
26
+ VALUE app_name = rb_hash_aref(token, rb_str_new2("app_name"));
27
+ VALUE flag1 = rb_hash_aref(token, rb_str_new2("flags1"));
28
+ VALUE flag2 = rb_hash_aref(token, rb_str_new2("flags2"));
29
+
30
+ strcpy(dpdata->Blob, rb_string_value_cstr(&blob));
31
+ strncpy(dpdata->Serial, rb_string_value_cstr(&serial), sizeof(dpdata->Serial));
32
+ strncpy(dpdata->AppName, rb_string_value_cstr(&app_name), sizeof(dpdata->AppName));
33
+ dpdata->DPFlags[0] = rb_fix2int(flag1);
34
+ dpdata->DPFlags[1] = rb_fix2int(flag2);
35
+ }
36
+
37
+ static void digipass_to_rbhash(TDigipassBlob* dpdata, VALUE hash) {
38
+ char buffer[256];
39
+
40
+ memset(buffer, 0, sizeof(buffer));
41
+ strncpy(buffer, dpdata->Serial, 10);
42
+ rb_hash_aset(hash, rb_str_new2("serial"), rb_str_new2(buffer));
43
+
44
+ memset(buffer, 0, sizeof(buffer));
45
+ strncpy(buffer, dpdata->AppName, 12);
46
+ rb_hash_aset(hash, rb_str_new2("app_name"), rb_str_new2(buffer));
47
+
48
+ memset(buffer, 0, sizeof(buffer));
49
+ strncpy(buffer, dpdata->Blob, 224);
50
+ rb_hash_aset(hash, rb_str_new2("blob"), rb_str_new2(buffer));
51
+
52
+ rb_hash_aset(hash, rb_str_new2("flags1"), rb_fix_new(dpdata->DPFlags[0]));
53
+ rb_hash_aset(hash, rb_str_new2("flags2"), rb_fix_new(dpdata->DPFlags[1]));
54
+ }
55
+
56
+ /*
57
+ * Get library version and return it as an hash
58
+ */
59
+ static VALUE vacman_library_version(VALUE module) {
60
+ aat_ascii version[16];
61
+ aat_int32 version_len = sizeof(version);
62
+
63
+ aat_ascii bitness[4];
64
+ aat_int32 bitness_len = sizeof(bitness);
65
+
66
+ aat_ascii type[8];
67
+ aat_int32 type_len = sizeof(type);
68
+
69
+ aat_int32 result = AAL2GetLibraryVersion(version, &version_len, bitness,
70
+ &bitness_len, type, &type_len);
71
+
72
+ if (result != 0) {
73
+ vacman_raise_error("AAL2GetLibraryVersion", result);
74
+ return Qnil;
75
+ }
76
+
77
+ VALUE hash = rb_hash_new();
78
+ rb_hash_aset(hash, rb_str_new2("version"), rb_str_new2(version));
79
+ rb_hash_aset(hash, rb_str_new2("bitness"), rb_str_new2(bitness));
80
+ rb_hash_aset(hash, rb_str_new2("type"), rb_str_new2(type));
81
+
82
+ return hash;
83
+ }
84
+
85
+
86
+ /*
87
+ * generate a password
88
+ * this will not work with all the dpx files available, it must be prepared for it
89
+ */
90
+ static VALUE vacman_generate_password(VALUE module, VALUE token) {
91
+ TDigipassBlob dpdata;
92
+
93
+ rbhash_to_digipass(token, &dpdata);
94
+
95
+ aat_ascii password[18];
96
+ memset(password, 0, sizeof(password));
97
+
98
+ aat_int32 result = AAL2GenPassword(&dpdata, &KernelParms, password, NULL);
99
+ digipass_to_rbhash(&dpdata, token);
100
+
101
+ if (result != 0) {
102
+ vacman_raise_error("AAL2GenPassword", result);
103
+ return Qnil;
104
+ }
105
+
106
+ return rb_str_new2(password);
107
+ }
108
+
109
+
110
+ /*
111
+ * Properties names and IDs registry
112
+ */
113
+ struct token_property {
114
+ char *name;
115
+ aat_int32 id;
116
+ };
117
+ static struct token_property token_properties[] = {
118
+ {"token_model", TOKEN_MODEL },
119
+ {"token_status", TOKEN_STATUS },
120
+ {"use_count", USE_COUNT },
121
+ {"last_time_used", LAST_TIME_USED },
122
+ {"last_time_shift", LAST_TIME_SHIFT },
123
+ {"time_based_algo", TIME_BASED_ALGO },
124
+ {"event_based_algo", EVENT_BASED_ALGO },
125
+ {"pin_supported", PIN_SUPPORTED },
126
+ {"unlock_supported", UNLOCK_SUPPORTED },
127
+ {"pin_ch_on", PIN_CH_ON },
128
+ {"pin_change_enabled", PIN_CH_ON },
129
+ {"pin_len", PIN_LEN },
130
+ {"pin_length", PIN_LEN },
131
+ {"pin_min_len", PIN_MIN_LEN },
132
+ {"pin_minimum_length", PIN_MIN_LEN },
133
+ {"pin_enabled", PIN_ENABLED },
134
+ {"pin_ch_forced", PIN_CH_FORCED },
135
+ {"pin_change_forced", PIN_CH_FORCED },
136
+ {"virtual_token_type", VIRTUAL_TOKEN_TYPE },
137
+ {"virtual_token_grace_period", VIRTUAL_TOKEN_GRACE_PERIOD },
138
+ {"virtual_token_remain_use", VIRTUAL_TOKEN_REMAIN_USE },
139
+ {"last_response_type", LAST_RESPONSE_TYPE },
140
+ {"error_count", ERROR_COUNT },
141
+ {"event_value", EVENT_VALUE },
142
+ {"last_event_value", LAST_EVENT_VALUE },
143
+ {"sync_windows", SYNC_WINDOWS },
144
+ {"primary_token_enabled", PRIMARY_TOKEN_ENABLED },
145
+ {"virtual_token_supported", VIRTUAL_TOKEN_SUPPORTED },
146
+ {"virtual_token_enabled", VIRTUAL_TOKEN_ENABLED },
147
+ {"code_word", CODE_WORD },
148
+ {"auth_mode", AUTH_MODE },
149
+ {"ocra_suite", OCRA_SUITE },
150
+ {"derivation_supported", DERIVATION_SUPPORTED },
151
+ {"max_dtf_number", MAX_DTF_NUMBER },
152
+ {"response_len", RESPONSE_LEN },
153
+ {"response_length", RESPONSE_LEN },
154
+ {"response_format", RESPONSE_FORMAT },
155
+ {"response_chk", RESPONSE_CHK },
156
+ {"response_checksum", RESPONSE_CHK },
157
+ {"time_step", TIME_STEP },
158
+ {"use_3des", TRIPLE_DES_USED },
159
+ {"triple_des_used", TRIPLE_DES_USED },
160
+ };
161
+
162
+ static size_t properties_count = sizeof(token_properties)/sizeof(struct token_property);
163
+
164
+ /*
165
+ * Convert property name to property ID
166
+ */
167
+ static long vacman_get_property_id(char *property_name) {
168
+ for (int i = 0; i < properties_count; i++) {
169
+ if (strcmp(property_name, token_properties[i].name) == 0) {
170
+ return token_properties[i].id;
171
+ }
172
+ }
173
+
174
+ rb_raise(e_vacmanerror, "Invalid property name `%s'", property_name);
175
+ return 0;
176
+ }
177
+
178
+
179
+ /*
180
+ * Get token properties
181
+ */
182
+ static VALUE vacman_get_token_property(VALUE module, VALUE token, VALUE property) {
183
+ TDigipassBlob dpdata;
184
+ rbhash_to_digipass(token, &dpdata);
185
+
186
+ aat_ascii value[64];
187
+ aat_int32 property_id = vacman_get_property_id(StringValueCStr(property));
188
+ aat_int32 result = AAL2GetTokenProperty(&dpdata, &KernelParms, property_id, value);
189
+
190
+ if (result == 0) {
191
+ return rb_str_new2(value);
192
+ } else {
193
+ vacman_raise_error("AAL2GetTokenProperty", result);
194
+ return Qnil;
195
+ }
196
+ }
197
+
198
+
199
+ /*
200
+ * Set token properties
201
+ */
202
+ static VALUE vacman_set_token_property(VALUE module, VALUE token, VALUE property, VALUE rbval) {
203
+ TDigipassBlob dpdata;
204
+
205
+ aat_int32 property_id = vacman_get_property_id(StringValueCStr(property));
206
+ aat_int32 value = rb_fix2int(rbval);
207
+
208
+ rbhash_to_digipass(token, &dpdata);
209
+
210
+ aat_int32 result = AAL2SetTokenProperty(&dpdata, &KernelParms, property_id, value);
211
+
212
+ digipass_to_rbhash(&dpdata, token);
213
+
214
+ if (result == 0) {
215
+ return Qtrue;
216
+ } else {
217
+ vacman_raise_error("AAL2SetTokenProperty", result);
218
+ return Qnil;
219
+ }
220
+ }
221
+
222
+
223
+ /*
224
+ * verify password
225
+ * this is the main usecase, check the use input for authentication
226
+ */
227
+ static VALUE vacman_verify_password(VALUE module, VALUE token, VALUE password ) {
228
+ TDigipassBlob dpdata;
229
+
230
+ rbhash_to_digipass(token, &dpdata);
231
+
232
+ aat_int32 result = AAL2VerifyPassword(&dpdata, &KernelParms, rb_string_value_cstr(&password), 0);
233
+
234
+ digipass_to_rbhash(&dpdata, token);
235
+
236
+ if (result == 0)
237
+ return Qtrue;
238
+ else {
239
+ vacman_raise_error("AAL2VerifyPassword", result);
240
+ return Qnil;
241
+ }
242
+ }
243
+
244
+
245
+
246
+ /*
247
+ * Import a .DPX file containing token seeds and initialisation values.
248
+ *
249
+ * Pass the pre-shared key to validate it as the second argument. Or if
250
+ * you don't have the key, replace the DC line with one from a file you
251
+ * know the key. Yes.
252
+ */
253
+ static VALUE vacman_import(VALUE module, VALUE filename, VALUE key) {
254
+ TDPXHandle dpx_handle;
255
+ aat_int16 appl_count;
256
+ aat_ascii appl_names[13*8];
257
+ aat_int16 token_count;
258
+
259
+ aat_int32 result = AAL2DPXInit(&dpx_handle, rb_string_value_cstr(&filename), rb_string_value_cstr(&key),
260
+ &appl_count, appl_names, &token_count);
261
+
262
+ if (result != 0) {
263
+ vacman_raise_error("AAL2DPXInit", result);
264
+ return Qnil;
265
+ }
266
+
267
+ aat_ascii sw_out_serial_No[22+1];
268
+ aat_ascii sw_out_type[5+1];
269
+ aat_ascii sw_out_authmode[2+1];
270
+ TDigipassBlob dpdata;
271
+
272
+ VALUE list = rb_ary_new();
273
+
274
+ while (1) {
275
+ result = AAL2DPXGetToken(&dpx_handle,
276
+ &KernelParms,
277
+ appl_names,
278
+ sw_out_serial_No,
279
+ sw_out_type,
280
+ sw_out_authmode,
281
+ &dpdata);
282
+
283
+
284
+ if (result < 0) {
285
+ vacman_raise_error("AAL2DPXGetToken", result);
286
+ return Qnil;
287
+ }
288
+ if (result == 107) break;
289
+
290
+ VALUE hash = rb_hash_new();
291
+
292
+ digipass_to_rbhash(&dpdata, hash);
293
+
294
+ rb_ary_push(list, hash);
295
+ }
296
+
297
+ AAL2DPXClose(&dpx_handle);
298
+
299
+ return list;
300
+ }
301
+
302
+ struct kernel_property {
303
+ char *name;
304
+ aat_int32 *value;
305
+ aat_int32 deflt;
306
+ };
307
+ static struct kernel_property kernel_properties[] = {
308
+ { "ITimeWindow", &KernelParms.ITimeWindow, 30 }, // Identification Window size in time steps
309
+ { "STimeWindow", &KernelParms.STimeWindow, 24 }, // Signature Window size in secs
310
+ { "DiagLevel", &KernelParms.DiagLevel, 0 }, // Requested Diagnostic Level
311
+ { "GMTAdjust", &KernelParms.GMTAdjust, 0 }, // GMT Time adjustment to perform
312
+ { "CheckChallenge", &KernelParms.CheckChallenge, 0 }, // Verify Challenge Corrupted (mandatory for Gordian)
313
+ { "IThreshold", &KernelParms.IThreshold, 3 }, // Identification Error Threshold
314
+ { "SThreshold", &KernelParms.SThreshold, 1 }, // Signature Error Threshold
315
+ { "ChkInactDays", &KernelParms.ChkInactDays, 0 }, // Check Inactive Days
316
+ { "DeriveVector", &KernelParms.DeriveVector, 0 }, // Vector used to make Data Encryption unique
317
+ { "SyncWindow", &KernelParms.SyncWindow, 2 }, // Synchronisation Time Window (h)
318
+ { "OnLineSG", &KernelParms.OnLineSG, 2 }, // On line signature
319
+ { "EventWindow", &KernelParms.EventWindow, 100 }, // Event Window size in nbr of iterations
320
+ { "HSMSlotId", &KernelParms.HSMSlotId, 0 }, // HSM Slot id uses to store DB and Transport Key
321
+ };
322
+ static int kernel_properties_count = sizeof(kernel_properties)/sizeof(struct kernel_property);
323
+
324
+ /*
325
+ * Set kernel parameter
326
+ */
327
+ static VALUE vacman_set_kernel_param(VALUE module, VALUE paramname, VALUE rbval) {
328
+ char *name = StringValueCStr(paramname);
329
+ int value = rb_fix2int(rbval);
330
+
331
+ for (int i = 0; i < kernel_properties_count; i++) {
332
+ if (strcmp(name, kernel_properties[i].name) == 0) {
333
+ *kernel_properties[i].value = value;
334
+ return Qtrue;
335
+ }
336
+ }
337
+
338
+ rb_raise(e_vacmanerror, "Invalid kernel param %s", name);
339
+ return Qnil;
340
+ }
341
+
342
+
343
+ /*
344
+ * Get kernel parameter
345
+ */
346
+ static VALUE vacman_get_kernel_param(VALUE module, VALUE paramname) {
347
+ char *name = StringValueCStr(paramname);
348
+
349
+ for (int i = 0; i < kernel_properties_count; i++) {
350
+ if (strcmp(name, kernel_properties[i].name) == 0) {
351
+ return LONG2FIX(*kernel_properties[i].value);
352
+ }
353
+ }
354
+
355
+ rb_raise(e_vacmanerror, "Invalid kernel param %s", name);
356
+ return Qnil;
357
+ }
358
+
359
+ /*
360
+ * Init the kernel parameters, with their defaults
361
+ */
362
+ static void init_kernel_params() {
363
+ memset(&KernelParms, 0, sizeof(TKernelParms));
364
+
365
+ KernelParms.ParmCount = 19; /* Number of valid parameters in this list */
366
+
367
+ for (int i = 0; i < kernel_properties_count; i++) {
368
+ *kernel_properties[i].value = kernel_properties[i].deflt;
369
+ }
370
+ }
371
+
372
+
373
+ /*
374
+ * rubys entry point to load the extension
375
+ */
376
+ void Init_vacman_controller(void) {
377
+ VALUE vacman_module = rb_define_module("VacmanLowLevel");
378
+
379
+ e_vacmanerror = rb_define_class("VacmanError", rb_eStandardError);
380
+ init_kernel_params();
381
+
382
+ rb_define_singleton_method(vacman_module, "version", vacman_library_version, 0);
383
+
384
+ rb_define_singleton_method(vacman_module, "import", vacman_import, 2);
385
+
386
+ rb_define_singleton_method(vacman_module, "generate_password", vacman_generate_password, 1);
387
+ rb_define_singleton_method(vacman_module, "verify_password", vacman_verify_password, 2);
388
+
389
+ rb_define_singleton_method(vacman_module, "get_kernel_param", vacman_get_kernel_param, 1);
390
+ rb_define_singleton_method(vacman_module, "set_kernel_param", vacman_set_kernel_param, 2);
391
+
392
+ rb_define_singleton_method(vacman_module, "get_token_property", vacman_get_token_property, 2);
393
+ rb_define_singleton_method(vacman_module, "set_token_property", vacman_set_token_property, 3);
394
+ }
@@ -0,0 +1,141 @@
1
+ require 'vacman_controller/vacman_controller'
2
+
3
+ # Provides VACMAN Controller functionality to identify and authorize user via VASCO DIGIPASS tokens.
4
+ #
5
+ #
6
+ 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
+ # Get a kernel parameter, wich is a basically a setting for vacman controller
68
+ #
69
+ # == Parameters:
70
+ # name::
71
+ # the param name. Most TKernelParms struct elements are accessible.
72
+ #
73
+ def get_kernel_param(name)
74
+ VacmanLowLevel.get_kernel_param(name)
75
+ end
76
+
77
+
78
+
79
+ # Change a kernel parameter, wich is a basically a setting for vacman controller
80
+ #
81
+ # == Parameters:
82
+ # name::
83
+ # the param name. Most TKernelParms struct elements are accessible.
84
+ # val::
85
+ # the fixnum value
86
+ #
87
+ def set_kernel_param(name, val)
88
+ VacmanLowLevel.set_kernel_param(name, val)
89
+ end
90
+
91
+
92
+
93
+ # Get a token single property
94
+ #
95
+ # == Parameters:
96
+ # hash::
97
+ # the hash for a specific token (you get these in import)
98
+ # property::
99
+ # the property names
100
+ #
101
+ # possible names:
102
+ #
103
+ # token_model
104
+ # use_count
105
+ # last_time_used
106
+ # last_time_shift
107
+ # time_based_algo
108
+ # event_based_algo
109
+ # pin_supported
110
+ # unlock_supported
111
+ # pin_change_enabled
112
+ # pin_length
113
+ # pin_minimum_length
114
+ # pin_enabled
115
+ # pin_change_forced
116
+ # virtual_token_type
117
+ # virtual_token_grace_period
118
+ # virtual_token_remain_use
119
+ # last_response_type
120
+ # error_count
121
+ # event_value
122
+ # last_event_value
123
+ # sync_windows
124
+ # primary_token_enabled
125
+ # virtual_token_supported
126
+ # virtual_token_enabled
127
+ # code_word
128
+ # auth_mode
129
+ # ocra_suite
130
+ # derivation_supported
131
+ # max_dtf_number
132
+ # response_length
133
+ # response_format
134
+ # response_checksum
135
+ # time_step
136
+ # use_3des
137
+ #
138
+ def get_token_property(hash, property)
139
+ VacmanLowLevel.get_token_property(hash, property)
140
+ end
141
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vacman_controller
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Marcus Lankenau
8
+ - Marcello Barnaba
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2019-01-04 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake-compiler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ description: Authenticate user via vacman controller
29
+ email:
30
+ - marcus.lankenau@gmail.com
31
+ - marcello.barnaba@gmail.com
32
+ executables: []
33
+ extensions:
34
+ - ext/vacman_controller/extconf.rb
35
+ extra_rdoc_files: []
36
+ files:
37
+ - ext/vacman_controller/extconf.rb
38
+ - ext/vacman_controller/vacman_controller.c
39
+ - lib/vacman_controller.rb
40
+ homepage: http://github.com/ifad/vacman_controller
41
+ licenses: []
42
+ metadata: {}
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubyforge_project:
59
+ rubygems_version: 2.5.2.1
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: Access to the vacman controller library
63
+ test_files: []