Index: openacs-4/packages/proctoring-support/proctoring-support.info
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/proctoring-support/proctoring-support.info,v
diff -u -r1.1.2.16 -r1.1.2.17
--- openacs-4/packages/proctoring-support/proctoring-support.info 14 Jun 2021 15:35:18 -0000 1.1.2.16
+++ openacs-4/packages/proctoring-support/proctoring-support.info 16 Jun 2021 11:26:54 -0000 1.1.2.17
@@ -10,7 +10,7 @@
f
proctoring
-
+
Antonio Pisano
Set of tools to implement proctoring of user interaction
Wirtschaftsuniversität Wien
@@ -21,7 +21,7 @@
No real UI is provided by the package itself. Other packages must integrate the provided includes.
0
-
+
Index: openacs-4/packages/proctoring-support/sql/postgresql/proctoring-support-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/proctoring-support/sql/postgresql/proctoring-support-create.sql,v
diff -u -r1.1.2.4 -r1.1.2.5
--- openacs-4/packages/proctoring-support/sql/postgresql/proctoring-support-create.sql 9 Jun 2021 15:55:53 -0000 1.1.2.4
+++ openacs-4/packages/proctoring-support/sql/postgresql/proctoring-support-create.sql 16 Jun 2021 11:26:54 -0000 1.1.2.5
@@ -54,17 +54,13 @@
proctoring_examination_statement_acceptance(user_id);
create table proctoring_safe_exam_browser_conf (
- object_id integer primary key
- references acs_objects(object_id) on delete cascade,
- seb_file text not null -- the file created via the SEB
+ object_id integer primary key references acs_objects(object_id) on delete cascade,
+ seb_file text -- the file created via the SEB
-- exam configuration that will
-- configure the clients
-- accessing this proctored
-- object
- key text not null, -- the keys generated during the SEB
+ allowed_keys text not null, -- the keys generated during the SEB
-- configuration that have been allowed
-- access to this exam
);
-
-create index proctoring_safe_exam_browser_conf_object_id_idx on
- proctoring_safe_exam_browser_conf(object_id);
Fisheye: Tag 1.1 refers to a dead (removed) revision in file `openacs-4/packages/proctoring-support/sql/postgresql/upgrade/upgrade-1.5.1-2.0.0.sql'.
Fisheye: No comparison available. Pass `N' to diff?
Index: openacs-4/packages/proctoring-support/tcl/proctoring-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/proctoring-support/tcl/proctoring-procs.tcl,v
diff -u -r1.1.2.12 -r1.1.2.13
--- openacs-4/packages/proctoring-support/tcl/proctoring-procs.tcl 9 Jun 2021 15:55:54 -0000 1.1.2.12
+++ openacs-4/packages/proctoring-support/tcl/proctoring-procs.tcl 16 Jun 2021 11:26:55 -0000 1.1.2.13
@@ -47,7 +47,7 @@
{-start_time ""}
{-end_time ""}
{-seb_p false}
- {-seb_key ""}
+ {-seb_keys ""}
{-seb_file ""}
} {
Configures proctoring for specified object.
@@ -74,9 +74,12 @@
executed. No time check when not specified.
@param seb_p Does this object enforce the use of the Safe Exam
Browser?
- @param seb_key Key we checking against when enforcing the use of
- the Safe Exam Browser, created via the Safe Exam
- Browser configuration tool.
+ @param seb_keys Keys we check against when enforcing the use of
+ the Safe Exam Browser, created via the Safe Exam
+ Browser configuration tool. These can be a
+ ConfigKeyHash, just validating the browser's
+ configuration or a RequestHash, also validating
+ the platform-specific version of SEB in use.
@param seb_file .seb file that holds the valid configuration for
this exam. When provided, upon failing the check
the user will be sent the file so that they can
@@ -127,11 +130,10 @@
}
if {$seb_p} {
- if {$seb_key ne "" &&
- $seb_file ne ""} {
+ if {$seb_keys ne ""} {
::proctoring::seb::configure \
-object_id $object_id \
- -key $seb_key \
+ -allowed_keys $seb_keys \
-seb_file $seb_file
}
} else {
@@ -162,7 +164,7 @@
set proctoring_p false
set examination_statement_p false
set seb_p false
- set seb_key ""
+ set seb_keys {}
set seb_file ""
::xo::dc 0or1row is_proctored {
@@ -178,7 +180,7 @@
case when enabled_p then 'true' else 'false' end as enabled_p,
case when examination_statement_p then 'true' else 'false' end as examination_statement_p,
case when seb.object_id is not null then 'true' else 'false' end as seb_p,
- seb.key as seb_key,
+ seb.allowed_keys as seb_keys,
seb.seb_file
from proctoring_objects o
left join proctoring_safe_exam_browser_conf seb
@@ -199,7 +201,7 @@
proctoring_p $proctoring_p \
examination_statement_p $examination_statement_p \
seb_p $seb_p \
- seb_key $seb_key \
+ seb_keys $seb_keys \
seb_file $seb_file]
}
Index: openacs-4/packages/proctoring-support/tcl/safe-exam-browser-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/proctoring-support/tcl/safe-exam-browser-procs.tcl,v
diff -u -r1.1.2.3 -r1.1.2.4
--- openacs-4/packages/proctoring-support/tcl/safe-exam-browser-procs.tcl 14 Jun 2021 15:35:18 -0000 1.1.2.3
+++ openacs-4/packages/proctoring-support/tcl/safe-exam-browser-procs.tcl 16 Jun 2021 11:26:55 -0000 1.1.2.4
@@ -9,38 +9,42 @@
ad_proc -private ::proctoring::seb::configure {
-object_id:required
- -key:required
- -seb_file:required
+ -allowed_keys:required
+ {-seb_file ""}
} {
Stores the configuration for an exam
@param object_id id of the proctored object.
- @param key safe exam browser's key that will be used to validate
+ @param allowed_keys safe exam browser's keys that will be used to validate
against the request hash provided by the clients.
@param seb_file absolute path to a file that will store the
configuration for this exam. When served to a user
having the Safe Exam Browser installed, this file
will configure and optionally start the exam using
exactly the provided configuration.
} {
- set folder_path [acs_root_dir]/proctoring/seb/$object_id
- file mkdir -- $folder_path
+ if {$seb_file ne ""} {
+ set folder_path [acs_root_dir]/proctoring/seb/$object_id
+ file mkdir $folder_path
- set seb_file_path $folder_path/Conf.seb
+ set seb_file_path $folder_path/Conf.seb
- file rename -force -- $seb_file $seb_file_path
+ file rename -force -- $seb_file $seb_file_path
+ } else {
+ set seb_file_path ""
+ }
::xo::dc dml -prepare {
integer text text
text text
} save_conf {
insert into proctoring_safe_exam_browser_conf
- (object_id, key, seb_file)
+ (object_id, allowed_keys, seb_file)
values
- (:object_id, :key, :seb_file_path)
+ (:object_id, :allowed_keys, :seb_file_path)
on conflict (object_id)
do update set
- key = :key,
+ allowed_keys = :allowed_keys,
seb_file = :seb_file_path
}
}
@@ -71,29 +75,73 @@
Validates a Safe Exam Browser hash.
The hash is generated based on:
- - the SEB configuration
- - (optionally) the SEB version and platform
+ - the SEB configuration (ConfigKeyHash and RequestHash)
+ - the SEB version and platform (RequestHash only)
- the currently requested URL
@return boolean
} {
return [expr {[ns_md string -digest sha256 ${url}${key}] eq $hash}]
}
-ad_proc -private ::proctoring::this_url {} {
+ad_proc -private ::proctoring::seb::this_url {} {
Computes the currently requested URL, used to match against the
hash provided by the browser.
@return fully qualified URL
} {
set url [util_current_location][ns_conn url]
- if {[ns_conn query] ne ""} {
- append url ?[ns_conn query]
+ set query [ns_conn query]
+ if {$query ne ""} {
+ append url ?$query
}
return $url
}
+ad_proc -private ::proctoring::seb::get_hashes {} {
+ Gets the hashes provided by the browser, which we will check
+ against the configured keys.
+} {
+ set hashes [list]
+
+ foreach h {
+ "X-SafeExamBrowser-RequestHash"
+ "X-SafeExamBrowser-ConfigKeyHash"
+ } {
+ set hash [ns_set get [ns_conn headers] $h]
+ if {$hash ne ""} {
+ lappend hashes $hash
+ }
+ }
+
+ return $hashes
+}
+
+ad_proc -private ::proctoring::seb::valid_access_p {
+ -allowed_keys:required
+} {
+ Check the hashes provided by the browser against the keys.
+
+ @return boolean
+} {
+ set url [::proctoring::seb::this_url]
+
+ foreach hash [::proctoring::seb::get_hashes] {
+ foreach key $allowed_keys {
+ set valid_access_p [::proctoring::seb::valid_hash_p \
+ -hash $hash \
+ -url $url \
+ -key $key]
+ if {$valid_access_p} {
+ return true
+ }
+ }
+ }
+
+ return false
+}
+
ad_proc -private ::proctoring::seb::require_valid_access {
-object_id:required
} {
@@ -104,25 +152,22 @@
unauthorized error.
} {
set seb_p [::xo::dc 0or1row -prepare integer get_seb_conf {
- select key, seb_file
+ select allowed_keys, seb_file
from proctoring_safe_exam_browser_conf
where object_id = :object_id
}]
if {$seb_p} {
- set hash [ns_set get [ns_conn headers] X-SafeExamBrowser-RequestHash]
- set url [::proctoring::this_url]
- set valid_access_p [::proctoring::seb::valid_hash_p \
- -hash $hash \
- -url $url \
- -key $key]
+ set valid_access_p [::proctoring::seb::valid_access_p \
+ -allowed_keys $allowed_keys]
} else {
set valid_access_p true
}
if {!$valid_access_p} {
if {[file exists $seb_file]} {
- ns_set cput [ns_conn outputheaders] Content-Disposition "attachment; filename=Config.seb"
+ ns_set cput [ns_conn outputheaders] \
+ Content-Disposition "attachment; filename=[file tail $filename]"
ns_writer submitfile -headers $seb_file
} else {
ns_returnunauthorized
Index: openacs-4/packages/proctoring-support/tcl/test/proctoring-test-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/proctoring-support/tcl/test/proctoring-test-procs.tcl,v
diff -u -r1.1.2.11 -r1.1.2.12
--- openacs-4/packages/proctoring-support/tcl/test/proctoring-test-procs.tcl 31 May 2021 12:40:02 -0000 1.1.2.11
+++ openacs-4/packages/proctoring-support/tcl/test/proctoring-test-procs.tcl 16 Jun 2021 11:26:55 -0000 1.1.2.12
@@ -51,6 +51,7 @@
::proctoring::configure
::proctoring::get_configuration
::proctoring::active_p
+ ::proctoring::seb::valid_hash_p
} \
proctoring_conf_test {
Test proctoring configuration api
@@ -78,6 +79,9 @@
desktop_p
proctoring_p
examination_statement_p
+ seb_p
+ seb_file
+ seb_keys
} {
aa_true "Field $field exists in dict" [dict exists $conf $field]
}
@@ -141,6 +145,58 @@
::proctoring::configure -object_id $object_id -camera_p true
set conf [::proctoring::get_configuration -object_id $object_id]
aa_true "Now proctoring appears to be on" [dict get $conf proctoring_p]
+
+ aa_log "Storing SEB configuration"
+ set key a3e85dcad0cd6a6e2f55e77399e4c9caf47807d760402d6b740017a9f0b2a197
+ set hash 6f3edc0ef5a56879eba206a7debb3fb0585ebb1f2423ebc10a1afce991edfbcd
+ set url https://learn-a.wu.ac.at:8081/dotlrn/classes/tlf/testkurs.17s/
+ set conf_file [ad_tmpnam]
+ set wfd [open $conf_file w]
+ puts $wfd abcd
+ close $wfd
+ set conf_file_hash [ns_md file $conf_file]
+
+ ::proctoring::configure \
+ -object_id $object_id \
+ -seb_p true \
+ -seb_keys $key
+ set conf [::proctoring::get_configuration -object_id $object_id]
+ aa_equals "Conf file is empty" [dict get $conf seb_file] ""
+ aa_equals "Key has been stored" [dict get $conf seb_keys] $key
+
+ set keys [list $key ${key}-2 ${key}-3]
+ ::proctoring::configure \
+ -object_id $object_id \
+ -seb_p true \
+ -seb_keys $keys
+ set conf [::proctoring::get_configuration -object_id $object_id]
+ aa_equals "Same number of keys are stored" [llength $keys] [llength [dict get $conf seb_keys]]
+ aa_equals "Exactly the same keys are stored" [lsort $keys] [lsort [dict get $conf seb_keys]]
+
+ ::proctoring::configure \
+ -object_id $object_id \
+ -seb_keys ${key}abcd
+ set conf [::proctoring::get_configuration -object_id $object_id]
+ aa_equals "Seb confs are deleted when the seb_p flag is false" \
+ "" [dict get $conf seb_keys]
+
+ ::proctoring::configure \
+ -object_id $object_id \
+ -seb_p true \
+ -seb_keys $key \
+ -seb_file $conf_file
+
+ set conf [::proctoring::get_configuration -object_id $object_id]
+ aa_equals "Conf file was stored correctly" \
+ [ns_md file [dict get $conf seb_file]] $conf_file_hash
+ aa_equals "Key was stored correctly" \
+ [dict get $conf seb_keys] $key
+
+ aa_true "Data has been stored correctly and the hash can be computed as expected" \
+ [::proctoring::seb::valid_hash_p \
+ -key [lindex [dict get $conf seb_keys] 0] \
+ -hash $hash \
+ -url $url]
}
}
@@ -207,6 +263,7 @@
file delete -- $file1 $file2
}
}
+
# Local variables:
# mode: tcl
# tcl-indent-level: 4