Skip to content

Commit

Permalink
Merge pull request #716 from DiamondLightSource/pre-release/2023-R5.2
Browse files Browse the repository at this point in the history
Pre Release 2023-R5.2 merge into Master
  • Loading branch information
NKatti2011 authored Jan 23, 2024
2 parents cd780d6 + 0afea90 commit 2aec48a
Show file tree
Hide file tree
Showing 23 changed files with 260 additions and 103 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,8 @@ jobs:
php_version: 7.3
version: 9

# Note, lint errors are being escaped here - so this will report, but not cause the build to fail
- name: Run Psalm
run: psalm --output-format=github || exit 0
run: psalm --output-format=github

js_build:
name: JavaScript build, test and lint
Expand Down
19 changes: 18 additions & 1 deletion api/config_sample.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@
# Update the ldap(s) prefix, hostname and search settings as required
$ldap_server = 'ldaps://ldap.example.com';
$ldap_search = 'ou=people,dc=example,dc=com';
# Specify the LDAP server type, can be either
# "openldap" (default) or "activedirectory"
$ldap_server_type = "openldap";
# If using "activedirectory" then specify the legacy domain name.
# i.e. "MYDOMAIN" rather than "mydomain.com"
# This will be prepended onto the username (e.g. MYDOMAIN\mylogin)
$active_directory_domain = "MYDOMAIN";
$ldap_use_tls = false; # default - i.e. don't use secured LDAP connection

# Upload directory
Expand All @@ -57,6 +64,9 @@
# - Show at the top of every page on first load
$motd = 'This is the message of the day.';

# Synchweb version, displayed in footer of each page
$synchweb_version = '';

# Maintainance Mode
# - Disables site access, showing a message
# - This is defined in client/js/config.json
Expand All @@ -67,6 +77,12 @@
# URL to access the PV archiver
$archive_url = '';

# URL to access elog logbook
$elog_base_url = '';
$elog_callouts_page = '';
$elog_ehc_page = '';


# Valid Components
# Denotes that only staff may create proteins, otherwise they must come from replication
# with a valid `externalid`, users may still clone proteins
Expand Down Expand Up @@ -307,7 +323,8 @@
array(
'name' => 'i03',
'group' => 'mx',
'archived' => False
'archived' => False,
'logbook' => 'BLI03'
),
array(
'name' => 'i04',
Expand Down
5 changes: 3 additions & 2 deletions api/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ function setupApplication($mode): Slim
global $motd, $authentication_type, $cas_url, $cas_sso, $sso_url, $package_description,
$facility_courier_countries, $facility_courier_countries_nde,
$dhl_enable, $dhl_link, $scale_grid, $scale_grid_end_date, $preset_proposal, $timezone,
$valid_components, $enabled_container_types, $ifsummary;
$valid_components, $enabled_container_types, $ifsummary, $synchweb_version;
$app->contentType('application/json');
$options = $app->container['options'];
$app->response()->body(json_encode(array(
Expand All @@ -90,7 +90,8 @@ function setupApplication($mode): Slim
'timezone' => $timezone,
'valid_components' => $valid_components,
'enabled_container_types' => $enabled_container_types,
'ifsummary' => $ifsummary
'ifsummary' => $ifsummary,
'synchweb_version' => $synchweb_version
)));
});
return $app;
Expand Down
28 changes: 23 additions & 5 deletions api/src/Authentication/Type/LDAP.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,44 @@ function check()

function authenticate($login, $password)
{
global $ldap_server, $ldap_search, $ldap_use_tls;
global $ldap_server, $ldap_search, $ldap_use_tls, $ldap_server_type, $active_directory_domain;
if (!$ldap_server_type) {
$ldap_search_type = "openldap";
}

$conn = ldap_connect($ldap_server);

if ($conn) {
// Tested against LDAP version 3 (could add support for older versions here)
/**
* @psalm-suppress UndefinedConstant
*/
ldap_set_option($conn, LDAP_OPT_PROTOCOL_VERSION, 3);

// use a secure connection for LDAP, if configured this way (default is unsecured as this was the historical setting)
if ($ldap_use_tls) {
ldap_start_tls($conn);
}

try {
// testing with openldap indicates this call needs to use a correct
// DN syntax: "uid=<login>,ou=people,dc=example,dc=com"
return ldap_bind($conn, "uid=" . $login . "," . $ldap_search, $password);
if ($ldap_server_type == "activedirectory") {
if (!$active_directory_domain) {
error_log("'active_directory_domain' parameter is not defined.");
error_log("\t This is required when LDAP server type is 'activedirectory'");
return false;
}
$ldap_user = $active_directory_domain . "\\" . $login;
} else {
// testing with openldap indicates this call needs to use a correct
// DN syntax: "uid=<login>,ou=people,dc=example,dc=com"
$ldap_user = "uid=" . $login . "," . $ldap_search;
}
return ldap_bind($conn, $ldap_user, $password);

// Couldn't bind
} catch (\Exception $e) {
error_log("SynchWeb - LDAP Auth FAILURE for user $login");
error_log("\t" . $e->getMessage());
error_log("\tldap_error: " . ldap_error($conn) . " (Err Code: " . ldap_errno($conn) . ")");
return false;
}
}
Expand Down
8 changes: 8 additions & 0 deletions api/src/Controllers/AuthenticationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,14 @@ function authenticateByCode()
$code = $this->app->request()->post('code');
$fedid = $this->authenticateByType()->authenticateByCode($code);
if ($fedid) {
/*
* Since the returned username might not be in the database, given it's returned by
* the SSO provider and not our internal authentication logic, we need to double check
* if it's valid
*/
if (!$this->dataLayer->isUserLoggedIn($fedid)) {
$this->returnError(403, 'User not recognised');
}
$this->returnResponse(200, $this->generateJwtToken($fedid));
} else {
$this->returnError(401, 'Invalid Credentials');
Expand Down
12 changes: 12 additions & 0 deletions api/src/Database/DatabaseQueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,16 @@ private function addBoundVariable($value): int
array_push($this->query_bound_values, $value);
return sizeof($this->query_bound_values);
}

public static function getWhereSearch($searchValue, $fields, &$query_bound_values)
{
$where = " AND (0=1";

foreach ($fields as $field) {
array_push($query_bound_values, $searchValue);
$where .= " OR lower(" . $field . ") LIKE lower(CONCAT('%', :" . sizeof($query_bound_values) . ", '%'))";
}
$where .= ")";
return $where;
}
}
3 changes: 3 additions & 0 deletions api/src/Page.php
Original file line number Diff line number Diff line change
Expand Up @@ -923,6 +923,9 @@ function _ldap_search($search, $email = False)
if ($ds)
{
// Explictly set the protocol version to prevent bind errors
/**
* @psalm-suppress UndefinedConstant
*/
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
$r = ldap_bind($ds);
$sr = ldap_search($ds, $ldap_search, $search);
Expand Down
13 changes: 11 additions & 2 deletions api/src/Page/Contact.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace SynchWeb\Page;

use SynchWeb\Page;
use SynchWeb\Database\DatabaseQueryBuilder;

class Contact extends Page
{
Expand Down Expand Up @@ -46,9 +47,17 @@ function _get_contacts() {
$where .= ' AND c.labcontactid=:'.(sizeof($args)+1);
array_push($args, $this->arg('cid'));
}


$tot = $this->db->pq("SELECT count(c.labcontactid) as tot FROM labcontact c $where", $args);
if ($this->has_arg('s')) {
$fields = array('pe.givenname', 'pe.familyname', 'c.cardname',
'l.name', 'l.address', 'l.city', 'l.country', 'pe.phonenumber', 'l.postcode');
$where = $where . DatabaseQueryBuilder::getWhereSearch($this->arg('s'), $fields, $args);
}

$tot = $this->db->pq("SELECT count(c.labcontactid) as tot FROM labcontact c
INNER JOIN person pe ON c.personid = pe.personid
INNER JOIN laboratory l ON l.laboratoryid = pe.laboratoryid
$where", $args);
$tot = intval($tot[0]['TOT']);

$pp = $this->has_arg('per_page') ? $this->arg('per_page') : 15;
Expand Down
6 changes: 3 additions & 3 deletions api/src/Page/Sample.php
Original file line number Diff line number Diff line change
Expand Up @@ -355,8 +355,8 @@ function _add_simple_sample()
$isCapillary = sizeof($crystals) > 1 ? true : false;

foreach ($crystals as $sample) {
$c = array();
foreach (array('SPACEGROUP', 'COMMENTS', 'NAME') as $f)
$c = array('NAME' => $phase->ACRONYM . '-sample');
foreach (array('SPACEGROUP', 'COMMENTS') as $f)
$c[$f] = array_key_exists($f, $sample) ? $sample->$f : '';
foreach (array('ABUNDANCE', 'THEORETICALDENSITY') as $f)
$c[$f] = array_key_exists($f, $sample) ? $sample->$f : null;
Expand Down Expand Up @@ -412,7 +412,7 @@ function _add_simple_sample()
if (array_key_exists('CAPILLARYID', $ids[$model]) && $capillary->CRYSTALID == null && !$capillary->CONTAINERLESS)
$blSamples['capillary'] = array('CONTAINERID' => $ids[$model]['CONTAINERID'], 'CRYSTALID' => $ids[$model]['CAPILLARYID'], 'PROTEINID' => $ids[$model]['CAPILLARYPHASEID'], 'LOCATION' => ++$maxLocation, 'NAME' => $capillary->NAME, 'PACKINGFRACTION' => 1, 'COMMENTS' => array_key_exists('COMMENTS', $capillary) ? $capillary->COMMENTS : '', 'DIMENSION1' => $capillary->OUTERDIAMETER, 'DIMENSION2' => $capillary->INNERDIAMETER, 'DIMENSION3' => $capillary->LENGTH, 'SHAPE' => $capillary->SHAPE, 'LOOPTYPE' => 1);

$blSamples['sample'] = array('CONTAINERID' => $ids[$model]['CONTAINERID'], 'CRYSTALID' => $ids[$model]['CRYSTALID'], 'PROTEINID' => $ids[$model]['PHASEID'], 'LOCATION' => ++$maxLocation, 'NAME' => $crystal->NAME, 'PACKINGFRACTION' => $attrs->PACKINGFRACTION ? $attrs->PACKINGFRACTION : null, 'COMMENTS' => array_key_exists('COMMENTS', $crystal) ? $crystal->COMMENTS : '');
$blSamples['sample'] = array('CONTAINERID' => $ids[$model]['CONTAINERID'], 'CRYSTALID' => $ids[$model]['CRYSTALID'], 'PROTEINID' => $ids[$model]['PHASEID'], 'LOCATION' => ++$maxLocation, 'NAME' => $phase->ACRONYM, 'PACKINGFRACTION' => $attrs->PACKINGFRACTION ? $attrs->PACKINGFRACTION : null, 'COMMENTS' => array_key_exists('COMMENTS', $crystal) ? $crystal->COMMENTS : '');

foreach ($blSamples as $key => $blSample) {
$a = $this->_prepare_sample_args($blSample);
Expand Down
15 changes: 12 additions & 3 deletions api/src/Page/Shipment.php
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ function _dewar_registry()
$tot = $this->db->pq("SELECT count(r.facilitycode) as tot
FROM dewarregistry r
LEFT OUTER JOIN dewarregistry_has_proposal rhp ON r.dewarregistryid = rhp.dewarregistryid
LEFT OUTER JOIN proposal p ON p.proposalid = r.proposalid
LEFT OUTER JOIN proposal p ON p.proposalid = rhp.proposalid
WHERE $where", $args);
$tot = intval($tot[0]['TOT']);

Expand Down Expand Up @@ -672,7 +672,11 @@ function _update_dewar_registry()
if (!$this->has_arg('FACILITYCODE'))
$this->_error('No dewar code specified');

$dew = $this->db->pq("SELECT facilitycode FROM dewarregistry WHERE facilitycode LIKE :1 AND proposalid = :2", array($this->arg('FACILITYCODE'), $this->proposalid));
$dew = $this->db->pq("SELECT facilitycode FROM dewarregistry dr
INNER JOIN dewarregistry_has_proposal drhp ON dr.dewarregistryid = drhp.dewarregistryid
WHERE dr.facilitycode LIKE :1
AND drhp.proposalid = :2",
array($this->arg('FACILITYCODE'), $this->proposalid));

if (!sizeof($dew))
$this->_error('No such dewar');
Expand Down Expand Up @@ -2891,7 +2895,12 @@ function _create_awb()

$ship['DELIVERYAGENT_FLIGHTCODE'] = $awb['awb'];
} catch (\Exception $e) {
$this->_error($e->getMessage());
if (Utils::getValueOrDefault($use_shipping_service_incoming_shipments) && $accno === $dhl_acc){
$error_response = json_decode($e->getMessage());
$this->_error($error_response->content->detail, $error_response->status);
} else {
$this->_error($e->getMessage());
}
}
}
$pickup = null;
Expand Down
67 changes: 52 additions & 15 deletions api/src/Page/Vstat.php
Original file line number Diff line number Diff line change
Expand Up @@ -687,15 +687,15 @@ function _error_log()
function _ehc_log()
{
$info = $this->_check_visit();
$elog_url = $this->_construct_elog_url($info, false);

$en = strtotime($info['EN']);
$ehc_tmp = $this->_get_remote_xml('https://rdb.pri.diamond.ac.uk/php/elog/cs_logwscontentinfo.php?startdate=' . date('d/m/Y', $en));
if (!$ehc_tmp)
if ($elog_url)
$ehc_tmp = $this->_get_remote_xml($elog_url);
if (!$elog_url || !$ehc_tmp)
$ehc_tmp = array();

$ehcs = array();
foreach ($ehc_tmp as $e) {
//if (strpos($e->title, 'shift') !== False)
array_push($ehcs, $e);
}

Expand All @@ -706,24 +706,61 @@ function _ehc_log()
function _callouts()
{
$info = $this->_check_visit();
$elog_url = $this->_construct_elog_url($info, true);
if ($elog_url)
$calls_tmp = $this->_get_remote_xml($elog_url);

if (!$elog_url || !$calls_tmp)
$calls_tmp = array();

$calls = array();
foreach ($calls_tmp as $e) {
array_push($calls, $e);
}
$this->_output($calls);
}


function _construct_elog_url($info, $callouts)
{
global $elog_base_url, $elog_callouts_page, $elog_ehc_page;
if (!$elog_base_url) {
return '';
}
$st = strtotime($info['ST']);
$en = strtotime($info['EN']);
if ($callouts) {
$page = $elog_callouts_page;
$parameters = array(
'startdate' => date('d/m/Y', $st),
'enddate' => date('d/m/Y', $en),
'selgroupid' => $this->_get_logbook_from_beamline($info['BL']),
);
} else {
$page = $elog_ehc_page;
$parameters = array('startdate' => date('d/m/Y', $en));
}

$bls = array(
'i02' => 'BLI02', 'i03' => 'BLI03', 'i04' => 'BLI04', 'i04-1' => 'BLI04J', 'i24' => 'BLI24', 'i23' => 'BLI23',
'i11-1' => 'BLI11',
'b21' => 'BLB21',
'i12' => 'BLI12', 'i13' => 'BLI13', 'i13-1' => 'BLI13J',
);
$calls = $this->_get_remote_xml('https://rdb.pri.diamond.ac.uk/php/elog/cs_logwscalloutinfo.php?startdate=' . date('d/m/Y', $st) . '&enddate=' . date('d/m/Y', $en) . 'selgroupid=' . $bls[$info['BL']]);
if (!$calls)
$calls = array();

$this->_output($calls);
$url_query = http_build_query($parameters);
$elog_url = $elog_base_url . $page . "?" . $url_query;
return $elog_url;
}


function _get_logbook_from_beamline($bl)
{
global $bl_types;
$logbook = null;
foreach ($bl_types as $type)
{
if ($type['name'] == $bl)
{
$logbook = $type['logbook'];
break;
}
}
return $logbook;
}


function _check_visit()
Expand Down
17 changes: 17 additions & 0 deletions api/tests/Controllers/AuthenticationControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ public function testCodeAuthenticationWhenGetValidFedIdReturnsSuccess(): void
$expectedFedID = "FedId012";
$_SERVER['HTTP_HOST'] = "host";

$this->dataLayerStub->method("isUserLoggedIn")->willReturn(true);

$this->setupSlimStubsRequestAndResponse(1, 1);
$authService = $this->setUpAuthControllerWithMockedAuthType("authenticateByCode", $expectedFedID);

Expand Down Expand Up @@ -214,4 +216,19 @@ public function testValidateAuthorisationRedirect(): void
$this->assertContains('Content-Type: application/json', Output::$headers);
$this->assertContains('X-PHP-Response-Code: 302', Output::$headers);
}

public function testReturnForbiddenIfUserIsNotRecognised(): void
{
$this->setupSlimStubsRequestAndResponse(1, 1);

$this->dataLayerStub->method("isUserLoggedIn")->willReturn(false);
$authService = $this->setUpAuthControllerWithMockedAuthType("authenticateByCode", "invalidFedId");

$this->expectExceptionOn( function () use ($authService){
$authService->authenticateByCode();
});

$this->assertContains('Content-Type: application/json', Output::$headers);
$this->assertContains('X-PHP-Response-Code: 403', Output::$headers);
}
}
Loading

0 comments on commit 2aec48a

Please sign in to comment.