-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathssoxs.module
1881 lines (1627 loc) · 65.8 KB
/
ssoxs.module
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?php
/**
* @file
* The main Single Sign On for eXternal Services module file.
*
* - Important helper classes and functions are loaded from
* includes/ssoxs_toolkit.inc
*/
module_load_include('inc', 'ssoxs', '/includes/ssoxs_toolkit');
/*-----------------------------------------------------------------
* Hook Implementations
*-----------------------------------------------------------------*/
/**
* Implements hook_help().
*
* - displays help and module information.
*/
function ssoxs_help($path, $arg) {
$sitename = variable_get('site_name', 'sitename');
$output = '';
switch ($path) {
case 'admin/help#ssoxs':
$output = '<div style="padding: 0px 37px 30px 37px;">' . t('This module implements a Single Sign On for eXternal Services
(SSOXS) functionality. Here, Drupal is used as central user management, authentication, authorization
and accounting service for external web services. Features include:
- Flexible registration of services for which to enable Single Sign On
- Users can register for services on their user account page
- Store SSO credentials locally or in a secure external database accessible to the service
- Powerful accounting functionality to track service usage and performance') . '</div>';
return $output;
case 'admin/config/services/ssoxs':
$output = '<div style="padding: 0px 37px 0px 37px;">' . t("This page provides an overview of all external services registered
to make use of the Single Sign On and accounting facility. Please use the <i>Add service</i> tab to register a
new service. The <i>Operations</i> icons provide links to various administration pages of each service
allowing to edit, manage registered users, view statistics and unregister the service respectively. The
number of pending users for a service is displayed in red") . '</div>';
return $output;
case 'admin/config/services/ssoxs/settings':
$output = '<div style="padding: 0px 37px 0px 37px;">' . t("The Single Sign On for eXternal Services module stores user, service,
and accounting information in the main site database or external database. The user information is
essentially the same as the user tables in the sites database. The module takes care of automatic
synchronisation of the two tables whenever there is a change in the subscription status of a sites user.
The Maintenance page allows for manual synchronisation of the user tables if needed.<br/><br/>Because
the user ssoxs db contains valuable information the module is equipped with a simple backup mechanism that
stores the content of the database as a text .sql file in the ssoxs directory of the default files location
of the Drupal installation. In case the powerful <i>backup and migrate</i> module is installed it will be used
instead of the buildin backup functionality. Backups are made periodicly controlled by the Drupal cron process.
Manual backups can be made at any time.<br/><br/>The SSOXS module can be configured to query a federate identity
provider for user authentication and authorization information allowing users to login to the VRC and make use of the
services using there own (institution) authentication information. The module uses the flexible <i>simpleSAMLphp</i>
library for this task. It needs to be properly installed and accesible.") . '</div>';
return $output;
case 'admin/config/services/ssoxs/%/statistics':
$output = '<div style="padding: 0px 37px 0px 37px;">' . t("This page lists accounting statistics that were stored
in the ssoxs database by the service. By default the statistics are compiled for the period ranging
from the first job deposited by the service up to the present day. The 'start date' and 'End date' datepicker
allows for generation of statistics for a custom time period.") . '</div>';
return $output;
case 'admin/config/services/ssoxs/%/jobs':
$output = '<div style="padding: 0px 37px 0px 37px;">' . t("List of all jobs accounted for by the service. The results can be
filtered by date, status and/or user name. Most table columns are sortable by clicking on the column header. Logs
available for a given job are indicated by the text balloon icon in the messages column. Click the icon to
view the log. Please note that the job ID often links to the job results page but it might no longer exist.") . '</div>';
return $output;
case 'admin/config/services/ssoxs/%/users':
$output = '<div style="padding: 0px 37px 0px 37px;">' . t("Lists the users that subscribed to the service together with their subscription
status and the total and active number of service submissions. The administration interface allows you to edit subscription
data for every user selected. Options:<ul>
<li>Tokens: if the service makes use of token based submission, the token balans for the users is shown and can be changed</li>
<li>Custom attributes: if the services defines custom attributes, these are listed and can be changed</li>
<li>Add new users: search for registered users using the autocompleted user search box and subscribe them to the service.
This will by pass the user subscription procedure on the users 'My Services' page</li>
<li>Contact: send emails to all selected users</li></ul>") . '</div>';
return $output;
case 'admin/config/services/ssoxs/%/delete':
$output = '<div style="padding: 0px 37px 0px 37px;">' . t("Delete the service entry from the service database. Optionally
remove the service statistics table from the database which is not recommended as all accounting information
is lost.") . '</div>';
return $output;
case 'admin/config/services/ssoxs/add_service':
$output = '<div style="padding: 0px 37px 0px 37px;">' . t("Use this form to register a new external service to make use of SSOXS.
<ul><li>Use the 'basic service information' field to provide the name of your service and it's URL.
Enter one or more Drupal registered users as service administrators. Subscription requests and portal status
messages will be send to these persons.</li><li>Use the 'Roles' field to fine tune who is able to subscribe to
and use your service based on the general 'roles' privileges system used throughout Drupal.</li><li>Indicate
the attributes (user information) you need for your service to work. Respect privacy and request only what is
truly needed. The user will have to agree with the data being shared</li><li>Communication between the SSOXS module
and your service is secured using Blowfish encryption technology. Use the 'XML-RPC API key' field to generate
your service specific API key to enable secure communication.</li><li>Use the 'Signup requirements' field to
specify additional requirements you may impose on new users subscribing to your service. These can be the
possession of a certificate validated on signup, approval by the service administrator, an agreement to
service license terms or the use of a Token based submission system.</li><li>If your service uses any
additional user attributes you ca use the 'Variable data fields' field to add these to the user account.</ul></li>") . '</div>';
return $output;
case 'admin/config/services/ssoxs/%':
$output = '<div style="padding: 0px 37px 0px 37px;">' . t("Use this form to edit the data for the services registered to make use of SSOXS.
<ul><li>Use the 'basic service information' field to provide the name of your service, it's URL and the IP address
that is allowed to communicate with SSOXS using the XML-RPC protocol. Enter one or more Drupal registered
users as service administrators. Subscription requests and portal status messages will be send to these
persons.</li><li>Use the 'Roles' field to fine tune who is able to subscribe to and use your service based on
the general 'roles' privileges system used throughout Drupal.</li><li>Communication between the SSOXS module
and your service is secured using Blowfish encryption technology. Use the 'XML-RPC API key' field to generate
your service specific API key to enable secure communication.</li><li>Use the 'Signup requirements' field to
specify additional requirements you may impose on new users subscribing to your service. These can be the
possession of a certificate validated on signup, approval by the service administrator, an agreement to
service license terms or the use of a Token based submission system.</li><li>If your service uses any
additional user attributes you ca use the 'Variable data fields' field to add these to the user account.</ul></li>") . '</div>';
return $output;
case 'user/%/services':
$output = '<p>' . t('<div class="welcome-text">Welcome to your personal @sitename services subscription page listing
all the services that you can subscribe to. A subscription allows you to use your @sitename login
credentials to authenticate to the service. Subscribing is as simple as clicking on the service name, follow
any subscription signup requirements and clicking the subscribe button.<br/>
Some services require subscription approval, you can follow the approval process on this page.
<hr/></div>', array('@sitename' => $sitename)) . '</p>';
return $output;
}
}
/**
* Implements hook_perm().
*
* - Valid permissions for this module.
* - Define permissions for administing the module. Fine tune on
* editing module settings and viewing them.
* - Define permissions for adding services. Fine tune on add, edit, view
* and delete. Edit means adding and changing, delete is separate and
* view is only view. Set permissions for own service or all services.
* - Define permissions for the 'My Services' tab as edit or not. Basically
* means rather or not a user sees the My Services tab.
*/
function ssoxs_permission() {
return array(
'administer module' => array(
'title' => t('Administer module'),
'description' => t('User is allowed to administer the module.'),
'restrict access' => TRUE,
),
'view admin pages' => array(
'title' => t('View admin pages'),
'description' => t('User is allowed access to the SSOXS service administration pages. This is a primary permission, finetune using additional permissions.'),
),
'edit My Services' => array(
'title' => t('Edit My Services'),
'description' => t('Display the "My Services" page as part of the users profile pages'),
),
'delete any service' => array(
'title' => t('Delete any service'),
'description' => t('User is allowed to remove any service on the SSOXS administration pages'),
'restrict access' => TRUE,
),
'delete own service' => array(
'title' => t('Delete own service'),
'description' => t('User is allowed to remove own service on the SSOXS administration pages'),
),
'edit any service' => array(
'title' => t('Edit any service'),
'description' => t('User is allowed to edit any service on the SSOXS administration pages'),
'restrict access' => TRUE,
),
'edit own service' => array(
'title' => t('Edit own service'),
'description' => t('User is allowed to edit own service on the SSOXS administration pages'),
),
'view any service' => array(
'title' => t('View any service'),
'description' => t('User is allowed to view the configuration of any service on the SSOXS administration pages'),
'restrict access' => TRUE,
),
'view own service' => array(
'title' => t('View own service'),
'description' => t('User is allowed to view the configuration of own services on the SSOXS administration pages'),
),
'add any service' => array(
'title' => t('Add any service'),
'description' => t('User is allowed register any service with SSOXS'),
'restrict access' => TRUE,
),
'add own service' => array(
'title' => t('Add own service'),
'description' => t('User is allowed register own service with SSOXS'),
),
);
}
/**
* Implements hook_xmlrpc().
*
* - To register xmlrpc enabled functions.
*/
function ssoxs_xmlrpc() {
// User authentication function.
$methods[] = array(
'ssoxs.authenticate',
'_ssoxs_authenticate',
array('array', 'string', 'string'),
t('Returns user array if authentication successful empty array if not.
Provide service machine name and Blowfish encrypted string as: "user name","user password as MD5 hash"'),
);
// Automatic login e.a. true single sign on.
$methods[] = array(
'ssoxs.autologin',
'_ssoxs_autologin',
array('array', 'string', 'string'),
t('Returns user array if authentication succeeded empty array if not.
Provide Blowfish encrypted string of certificate dn and user ip'),
);
// Service accounting function.
$methods[] = array(
'ssoxs.accounting',
'_ssoxs_accounting',
array('array', 'array'),
t('Perform accounting for a new or existing job.
accepts an array with; service machine name, user uid and ip, job id, job status, message and job url'),
);
// Query function to search for service users based on key and/or values in
// the user object.
$methods[] = array(
'ssoxs.query',
'_ssoxs_query',
array('array', 'array'),
t('Query the user table for a given service, returns a user object as array.
Provide service machine name and key/value pair to query for.'),
);
// Update service specific attributes of the user object.
$methods[] = array(
'ssoxs.update',
'_ssoxs_update',
array('array', 'array'),
t('Update the service specific attributes of the user object'),
);
return $methods;
}
/**
* Implements hook_theme().
*
* - Only the service statistics page needs a special theming function
*/
function ssoxs_theme() {
return array(
'ssoxs_service_statistics_form' => array(
'render element' => 'form',
'file' => 'includes/ssoxs_statistics.inc',
),
);
}
/**
* Implements hook_user_delete().
*
* - To remove a user from the synchronized ssoxs Drupal user table and
* unsubscribe them from all services.
*/
function ssoxs_user_delete($account) {
ssoxs_db_connect();
$services = db_select('ssoxs_services', 'n')->fields('n', array('machine_name'))->execute()->fetchCol();
foreach ($services as $service) {
$service_table = 'ssoxs_' . $service . '_users';
db_delete($service_table)->condition('uid', $account->uid, '=')->execute();
}
db_delete('ssoxs_users')->condition('uid', $account->uid, '=')->execute();
ssoxs_db_reset();
drupal_set_message(t('ssoxs: delete account data for user: <i>@name</i> from ssoxs db', array('@name' => $account->name)));
watchdog('ssoxs', 'Delete account data for user: %user from ssoxs db', array('%user' => $account->name), WATCHDOG_NOTICE);
}
/**
* Implements hook_user_update().
*
* - To update the synchronized ssoxs Drupal user table.
*/
function ssoxs_user_update(&$edit, $account, $category) {
ssoxs_db_connect();
db_update('ssoxs_users')
->fields(array(
'name' => $account->name,
'mail' => $account->mail,
'pass' => $account->pass,
))
->condition('uid', $account->uid, '=')
->execute();
ssoxs_db_reset();
watchdog('ssoxs', 'Update SSO account data for user: %user in ssoxs db', array('%user' => $account->name),
WATCHDOG_NOTICE, l(t('edit'), 'user/' . $account->uid . '/edit'));
}
/**
* Implements hook_user_login().
*
* - add users current IP to the ssoxs user table as flag that the user is
* logged into the site.
*/
function ssoxs_user_login(&$edit, $account) {
ssoxs_db_connect();
db_update('ssoxs_users')
->fields(array('ip' => ip_address()))
->condition('uid', $account->uid, '=')
->execute();
ssoxs_db_reset();
}
/**
* Implements hook_user_logout().
*
* - Removes IP from the ssoxs user table.
* - logout: if SAML based authentication and force authentication option
* selected, logout from SAML.
* - logout: if SAML based authentication created a local account, remove if
* ssoxs_saml_persist_account is FALSE.
*/
function ssoxs_user_logout($account) {
// Delete account if we are not allowed to persist a user account and it was
// created by SAML SSO authenticated user.
// Use Drupal authmap table to discover external users authenticated via
// ssoxs. Remove from authmaps if needed.
$saml_user = user_get_authmaps($account->name);
if ($saml_user == 0) {
$saml_user = array();
}
if (!variable_get('ssoxs_saml_persist_account', 1) and array_key_exists('ssoxs', $saml_user)) {
// Check once more if we have a uid, else there is a change we delete the
// anonymous user (0)
if ($account->uid) {
ssoxs_db_connect();
db_delete('ssoxs_users')->condition('uid', $account->uid, '=')->execute();
ssoxs_db_reset();
watchdog('ssoxs', 'Delete SAML SSO registered user: %user', array('%user' => $account->name), WATCHDOG_NOTICE);
db_delete('authmap')->condition('uid', $account->uid, '=')->execute();
user_delete_multiple(array($account->uid));
}
}
// Else, set IP to null in ssoxs_users, means no active session.
else {
ssoxs_db_connect();
db_update('ssoxs_users')->fields(array('ip' => NULL))->condition('uid', $account->uid, '=')->execute();
ssoxs_db_reset();
}
// If SAML based login does not allow persistent user sessions, logout the
// user in simpleSAMLphp.
if (variable_get('ssoxs_saml_enabled', 0)) {
$saml = new SsoxsSAMLAuth(variable_get('ssoxs_saml_lib_path', ''));
if ($saml->classIsInitiated) {
$saml->initAuthSource(variable_get('ssoxs_saml_idp', ''));
if (variable_get('ssoxs_saml_forceauth', 0) and $saml->samlInstance->isAuthenticated()) {
$saml->logout($account);
}
}
}
}
/**
* Implements hook_user_insert().
*
* - To insert the new user in the ssoxs user table.
*/
function ssoxs_user_insert(&$edit, $account, $category) {
ssoxs_db_connect();
db_insert('ssoxs_users')
->fields(array(
'uid' => $account->uid,
'name' => $account->name,
'pass' => $account->pass,
'mail' => $account->mail,
))
->execute();
ssoxs_db_reset();
drupal_set_message(t('ssoxs: new user <i>@name</i> added to ssoxs db', array('@name' => $account->name)));
watchdog('ssoxs', 'New user: %user added to ssoxs db', array('%user' => $account->name),
WATCHDOG_NOTICE, l(t('edit'), 'user/' . $account->uid . '/edit'));
}
/**
* Implements hook_menu().
*
* - Add ssoxs admin interface in the module settings and to add the
* "My Services" page to the user account page.
* - Access privileges to the various pages regulated by hook_perm, often
* accessed using ssoxs_service_permissions callback function.
* - The %service variable in the Drupal path calls the ssoxs_service_load
* function which uses the passed in service pid to fetch the service
* information from the database and returns it wrapped in a service class.
* - SSOXS SAML based login page only added to login menu if enabled on the
* SSOXS settings page. Cache might need to be cleared if this option is
* switched off.
*/
function ssoxs_menu() {
$items = array();
// Lists module in 'Services' group on main configuration page.
// Links to the SSOXS service overview page.
$items['admin/config/services/ssoxs'] = array(
'title' => 'SSOXS',
'description' => 'Single Sign On for eXternal Services.',
'page callback' => 'ssoxs_overview_page',
'file' => 'includes/ssoxs_overview.inc',
'access arguments' => array('view admin pages'),
'type' => MENU_NORMAL_ITEM,
);
// SSOXS service overview page.
$items['admin/config/services/ssoxs/list'] = array(
'title' => 'List',
'type' => MENU_DEFAULT_LOCAL_TASK,
);
// SSOXS register new service page.
$items['admin/config/services/ssoxs/add_service'] = array(
'title' => 'Add service',
'page callback' => 'ssoxs_addservice_page',
'access callback' => 'ssoxs_service_permissions',
'access arguments' => array(4, 'add'),
'file' => 'includes/ssoxs_services.inc',
'type' => MENU_LOCAL_TASK,
'weight' => 1,
);
// SSOXS module settings page.
$items['admin/config/services/ssoxs/settings'] = array(
'title' => 'Settings',
'page callback' => 'drupal_get_form',
'page arguments' => array('ssoxs_settingsform'),
'access callback' => 'ssoxs_service_permissions',
'access arguments' => array(4, 'view'),
'file' => 'includes/ssoxs_settings.inc',
'type' => MENU_LOCAL_TASK,
'weight' => 2,
);
// SSOXS edit service configuration page.
$items['admin/config/services/ssoxs/%ssoxs_service'] = array(
'page callback' => 'ssoxs_addservice_page',
'page arguments' => array(4),
'access callback' => 'ssoxs_service_permissions',
'access arguments' => array(4, 'view'),
'file' => 'includes/ssoxs_services.inc',
'type' => MENU_NORMAL_ITEM,
);
$items['admin/config/services/ssoxs/%ssoxs_service/edit'] = array(
'title' => 'Edit',
'file' => 'includes/ssoxs_services.inc',
'type' => MENU_DEFAULT_LOCAL_TASK,
'access callback' => 'ssoxs_service_permissions',
'access arguments' => array(4, 'edit'),
'weight' => 1,
);
// SSOXS service user administration page.
$items['admin/config/services/ssoxs/%ssoxs_service/users'] = array(
'title' => 'User management',
'page callback' => 'drupal_get_form',
'page arguments' => array('ssoxs_service_users_form', 4),
'access callback' => 'ssoxs_service_permissions',
'access arguments' => array(4, 'view'),
'file' => 'includes/ssoxs_useradmin.inc',
'type' => MENU_LOCAL_TASK,
'weight' => 2,
);
// SSOXS service job acounting page.
$items['admin/config/services/ssoxs/%ssoxs_service/jobs'] = array(
'title' => 'Accounting',
'page callback' => 'drupal_get_form',
'page arguments' => array('ssoxs_service_job_form', 4),
'access callback' => 'ssoxs_service_permissions',
'access arguments' => array(4, 'view'),
'file' => 'includes/ssoxs_jobadmin.inc',
'type' => MENU_LOCAL_TASK,
'weight' => 3,
);
// SSOXS service usage statistics page.
$items['admin/config/services/ssoxs/%ssoxs_service/statistics'] = array(
'title' => 'Service statistics',
'page callback' => 'drupal_get_form',
'page arguments' => array('ssoxs_service_statistics_form', 4),
'access callback' => 'ssoxs_service_permissions',
'access arguments' => array(4, 'view'),
'file' => 'includes/ssoxs_statistics.inc',
'type' => MENU_LOCAL_TASK,
'weight' => 4,
);
// SSOXS service uninstall customization page.
$items['admin/config/services/ssoxs/%ssoxs_service/unregister'] = array(
'title' => 'Unregister service',
'page callback' => 'drupal_get_form',
'page arguments' => array('ssoxs_service_delete_form', 4),
'access callback' => 'ssoxs_service_permissions',
'access arguments' => array(4, 'delete'),
'file' => 'includes/ssoxs_services.inc',
'type' => MENU_LOCAL_TASK,
'weight' => 5,
);
// SSOXS user profile 'My Services' page.
$items['user/%user/services'] = array(
'type' => MENU_LOCAL_TASK,
'title' => 'My services',
'page callback' => 'drupal_get_form',
'page arguments' => array('ssoxs_user_editservices_form', 1),
'access arguments' => array('edit My Services'),
'file' => 'includes/ssoxs_useraccount.inc',
);
// SSOXS SAML based login.
if (variable_get('ssoxs_saml_enabled', 0)) {
$items['user/SSO_login'] = array(
'page callback' => 'ssoxs_saml_login',
'access callback' => 'user_is_anonymous',
'type' => MENU_LOCAL_TASK,
'title' => 'Login with your ' . variable_get('ssoxs_saml_idp', '') . ' credentials',
'file' => 'includes/ssoxs_saml_login.inc',
'weight' => 2,
);
}
// SSOXS (ajax) callback functions for adding variable data fields.
$items['ssoxs/add_vdata'] = array(
'title' => 'Add variable field data to service',
'page callback' => '_ssoxs_vdata_add_callback',
'access callback' => 'ssoxs_service_permissions',
'file' => 'includes/ssoxs_services.inc',
'access arguments' => array(3, 'edit'),
'type' => MENU_CALLBACK,
);
// SSOXS (ajax) callback functions for autocompleting admin names.
$items['admin/config/ssoxs/autocomplete_admins'] = array(
'title' => 'Service administrator autocomplete',
'page callback' => '_ssoxs_autocomplete_admins_callback',
'access callback' => 'ssoxs_service_permissions',
'access arguments' => array(3, 'add'),
'file' => 'includes/ssoxs_services.inc',
'type' => MENU_CALLBACK,
);
// SSOXS (ajax) callback functions for checking IP's.
$items['admin/config/ssoxs/set_ip_by_url_callback'] = array(
'title' => 'Set service ip field based on service URL',
'page callback' => '_ssoxs_iptourl_callback',
'access callback' => 'ssoxs_service_permissions',
'access arguments' => array(3, 'add'),
'file' => 'includes/ssoxs_services.inc',
'type' => MENU_CALLBACK,
);
// SSOXS (ajax) callback functions for generating API key.
$items['admin/config/ssoxs/generate_api_key'] = array(
'title' => 'Generate an API key',
'page callback' => '_ssoxs_generate_key_callback',
'access callback' => 'ssoxs_service_permissions',
'access arguments' => array(3, 'add'),
'file' => 'includes/ssoxs_services.inc',
'type' => MENU_CALLBACK,
);
// SSOXS (ajax) callback functions for validating simpleSAMLphp path.
$items['admin/config/ssoxs/set_saml_lib_path_callback'] = array(
'title' => 'Validate SimpleSAMLphp library path',
'page callback' => '_ssoxs_validate_samllibpath_callback',
'access callback' => 'ssoxs_service_permissions',
'access arguments' => array(3, 'edit'),
'file' => 'includes/ssoxs_settings.inc',
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Implements hook_cron().
*
* - Run at daily intervals.
* - Check if there are users that are pending for more than 3 days.
* Send reminder email to administrators every tome cron runs (every day).
* - If the module uses an external database or if the "backup and migrate"
* module is not active, run backup the ssoxs SQL database to a .sql file in
* the ~/files/ssoxs directory using _ssoxs_backupSsoxsDatabase function.
* - soxs_saml_remove_inactive True: remove external user account if more than 6
* month of inactivity. Send email 1 month in advance.
*/
function ssoxs_cron() {
global $base_url;
// Set daily interval and store as variable.
$interval = variable_get('ssoxs_cron_interval', 86400);
// Check if it is time to run.
if (time() >= variable_get('ssoxs_cron_next_execution', 0)) {
// Task 1: Check if there are users pending for a while. send email to
// admin again.
ssoxs_db_connect();
$services = db_select('ssoxs_services')->fields('ssoxs_services', array('machine_name'))->execute()->fetchCol();
ssoxs_db_reset();
foreach ($services as $service) {
// Get number of users pending for the service more than 3 days
ssoxs_db_connect();
$pending_users = db_select('ssoxs_' . $service . '_users', 'n')
->fields('n', array('uid'))
->condition('n.subscription', 1, '=')
->condition('n.rdate', REQUEST_TIME + 259200, '>')
->countQuery()->execute()->fetchField();
ssoxs_db_reset();
// If pending users, send reminder mail to service admins.
if ($pending_users > 0) {
$service = new SsoxsService();
$service->getServiceByMachineName($service);
$admin_mail = array();
foreach ($service->admins as $admin) {
$admin_mail[] = $admin->mail;
}
$serviceurl = l(t($service->name), $base_url . '/admin/config/services/ssoxs/' . $service->pid . '/users');
$subject = t('User subscription approval reminder for @name', array('@name' => $service->name));
$message = t('Dear @name service administrator,<br/><br/>
There are still @pending awaiting approval for service subscription.<br/>
Please process there request at: @url <br/>',
array('@name' => $service->name, '@pending' => $pending_users, '@url' => $serviceurl));
_ssoxs_send_email($admin_mail, $subject, $message);
watchdog('ssoxs', 'User subscription approval reminder send to administrators of %service service', array('%service' => $service->name));
}
}
// Task 2: Run ssoxs database tables backup function if 'backup and
// migrate' module is not active or data is not stored in default (local)
// database.
if (!module_exists('backup_migrate') or variable_get('ssoxs_external_db_name', 'default') != 'default') {
_ssoxs_backupSsoxsDatabase();
}
// Task 3: Remove external user account if more than 6 month of inactivity.
// Send email 1 month in advance.
if (variable_get('ssoxs_saml_remove_inactive', FALSE)) {
_ssoxs_checkExternalUsersActivity();
}
watchdog('ssoxs', 'Run SSOXS cron tasks');
}
// Store new execution timepoint.
variable_set('ssoxs_cron_next_execution', time() + $interval);
}
/*-----------------------------------------------------------------
* Menu callbacks
*------------------------------------------------------------------*/
/**
* Control access to service pages for perms 'edit', 'view' and 'delete'.
*
* - Differentiate between access to any service or own service.
* - If '<category> any service' privilege, grant. If '<category>own service'
* and user uid equals service admin uid, grant.
* - Own service is matched against the array of service administrator uid's.
*
* @param class $service
* Service class to match service administrator uids against current user uid.
* @param string $access
* Privilege catagorie as 'edit', 'view' and 'delete'.
*
* @return bool
* Access granted TRUE or not FALSE.
*/
function ssoxs_service_permissions($service, $access) {
$granted = FALSE;
$granted = user_access("$access any service");
if (!$granted and user_access("$access own service")) {
global $user;
$granted = (in_array($user->uid, explode(',', $service->uid)));
}
return $granted;
}
/**
* Pickes up the services pid from the URL and returns the service instance.
*
* @param int $pid
* Service numeric identifier (pid) extracted from URL.
*
* @return class
* Service object matching the pid.
*/
function ssoxs_service_load($pid) {
$service = new SsoxsService();
$service->getServiceByPid($pid);
return $service;
}
/*-----------------------------------------------------------------
* Private methods
*------------------------------------------------------------------*/
/**
* Class to manage the variable data field of type 'text'
*/
class SsoxsAhahTextType {
protected $type = "SsoxsAhahTextType";
public $form;
public $delete = 0;
/**
* Class constructor.
*
* @param array $values
* Optional array of values to pre-populate the text type with database
* stored values.
*/
public function __construct($values = NULL) {
$this->form = $this->returnForm();
if (!is_null($values)) {
$this->fillForm($values);
}
}
/**
* Create the form elements for configuration of the text type.
*
* @return array
* Array of Drupal form elements.
*/
public function returnForm() {
$form = array();
$form['type'] = array(
'#type' => 'hidden',
'#value' => $this->type,
);
$form['var_name'] = array(
'#prefix' => '<div class="vdata-wrapper"><h3>Text field</h3>',
'#type' => 'textfield',
'#title' => t('Variable name'),
'#description' => t('Specify unique variable name, will be used as ID in the database'),
'#required' => TRUE,
);
$form['delete'] = array(
'#type' => 'checkbox',
'#title' => t('Remove variable'),
'#default_value' => 0,
'#prefix' => '<div class="delete-box">',
'#suffix' => '</div>',
);
$form['description'] = array(
'#type' => 'textfield',
'#title' => t('Description'),
'#description' => t('Description of the data fields purpose'),
);
$form['default_value'] = array(
'#type' => 'textfield',
'#title' => t('Default value'),
'#description' => t('Optional default value'),
'#suffix' => '</div>',
);
return $form;
}
/**
* Return public form items belonging to variable type.
*
* - returns array with Drupal form item of type textbox.
* - return empty array if no form element.
*/
public function returnPublicForm() {
$form = array();
$form[$this->form['var_name']['#default_value']] = array(
'#type' => 'textfield',
'#title' => t('@var (var id: @id)', array(
'@var' => $this->form['description']['#default_value'],
'@id' => $this->form['var_name']['#default_value'],
)),
);
return $form;
}
/**
* Update the default form fields for this type.
*
* - If the var_name is set it can no longer be changed.
* - Disable it and change required to FALSE.
* - Set the delete flag. If checked than this variable is no longer stored.
*/
public function fillForm($values) {
foreach ($values as $i => $v) {
if (array_key_exists($i, $this->form)) {
if ($i == 'var_name') {
if (array_key_exists('#default_value', $this->form[$i])) {
$this->form[$i]['#disabled'] = TRUE;
$this->form[$i]['#required'] = FALSE;
}
else {
$this->form[$i]['#default_value'] = _ssoxs_machine_name($v);
}
}
else {
if (empty($v)) {
$returnform = $this->returnForm();
$this->form[$i] = $returnform[$i];
}
else {
$this->form[$i]['#default_value'] = $v;
}
}
}
}
$this->delete = $this->form['delete']['#default_value'] or 0;
}
/**
* Return an array of values used to store the variable in the db.
*/
public function returnStorageArray() {
$storage_array = array('type' => $this->type);
foreach ($this->form as $i => $v) {
if (array_key_exists('#default_value', $v)) {
$storage_array[$i] = $v['#default_value'];
}
}
return $storage_array;
}
/**
* Add the new variable as column to the table using Drupals db_add_field.
*
* - Required table name as argument.
* - The var_name needs to be set, otherwise no table column key.
* - Make sure the db is set to 'ssoxs', we will not do it in this function
* as it might break the db calls in the code where this functioned is
* called.
*/
public function addColumnToTable($table) {
if (array_key_exists('#default_value', $this->form['var_name'])) {
$default = NULL;
if (array_key_exists('#default_value', $this->form['default_value'])) {
$default = $this->form['default_value']['#default_value'];
}
$schema_array = array(
'type' => 'varchar',
'length' => 128,
'not null' => (!is_null($default)) ? TRUE : FALSE,
'description' => $this->form['description']['#default_value'],
);
if (!is_null($default)) {
$schema_array['default'] = $default;
}
db_add_field($table, $this->form['var_name']['#default_value'], $schema_array);
}
}
}
class SsoxsAhahIntegerType {
/**
* Class to manage the variable data field of type 'integer'.
*/
protected $type = "SsoxsAhahIntegerType";
public $form;
public $delete = 0;
/**
* Class constructor.
*
* @param array $values
* Optional array of values to pre-populate the integer type with database
* stored values.
*/
public function __construct($values = NULL) {
$this->form = $this->returnForm();
if (!is_null($values)) {
$this->fillForm($values);
}
}
/**
* Create the form elements for configuration of the integer type.
*
* @return array
* Array of Drupal form elements.
*/
public function returnForm() {
$form = array();
$form['type'] = array(
'#type' => 'hidden',
'#value' => $this->type,
);
$form['var_name'] = array(
'#prefix' => '<div class="vdata-wrapper"><h3>Integer field</h3>',
'#type' => 'textfield',
'#title' => t('Variable name'),
'#description' => t('Specify unique variable name, will be used as ID in the database'),
'#required' => TRUE,
);
$form['delete'] = array(
'#type' => 'checkbox',
'#title' => t('Remove variable'),
'#default_value' => 0,
'#prefix' => '<div class="delete-box">',
'#suffix' => '</div>',
);
$form['description'] = array(
'#type' => 'textfield',
'#title' => t('Description'),
'#description' => t('Description of the data fields purpose'),
);
$form['default_value'] = array(
'#type' => 'textfield',
'#title' => t('Default value'),
'#description' => t('Optional default value'),
);
$form['neg_allowed'] = array(
'#type' => 'checkbox',
'#title' => t('Allow negative values'),
'#default_value' => 0,
'#suffix' => '</div>',
);
return $form;
}
/**
* Return public form items belonging to variable type.
*
* - returns array with Drupal form item of type textbox.
* - return empty array if no form element.