Skip to content

Commit

Permalink
Merge pull request #636 from DiamondLightSource/pre-release/2023-R3.2
Browse files Browse the repository at this point in the history
Pre release/2023 r3.2
  • Loading branch information
John-Holt-Tessella authored Jul 26, 2023
2 parents 9814675 + 0dbfe03 commit 20eba26
Show file tree
Hide file tree
Showing 39 changed files with 264 additions and 160 deletions.
1 change: 0 additions & 1 deletion api/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
"firebase/php-jwt": "2.2.0",
"jdorn/sql-formatter": "1.2.9",
"mpdf/mpdf": "8.1.2",
"phpxmlrpc/phpxmlrpc": "3.1.2",
"ralouphie/getallheaders": "2.0.5",
"slim/slim": "2.6.2",
"stomp-php/stomp-php": "3.0.6",
Expand Down
15 changes: 13 additions & 2 deletions api/config_sample.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@

# Follow CAS SSO
$cas_sso = true;
$sso_url = "sso.server.ac.uk";

// OIDC (or OAuth2) client ID and secret. Only useful if authentication_type is set to OIDC
# OIDC (or OAuth2) client ID and secret. Only useful if authentication_type is set to OIDC
$oidc_client_id = "oidcClientId";
$oidc_client_secret = "oidcClientSecret";
// Cookie key used for SSO/cookie based authentication
# Cookie key used for SSO/cookie based authentication
$cookie_key = "synchweb-auth";

# CAS CA Cert (for SSO)
Expand All @@ -58,6 +59,9 @@
# Timezone
$timezone = 'Europe/London';

# URL to access the PV archiver
$archive_url = '';

# 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 @@ -150,6 +154,13 @@
# and for shipment booked,
$shipbooked_email = '[email protected]';

# dewar back in storage (complete)
$dewar_complete_email = '';

# Send a 'visit finished' email when a dewar moves from this beamline to this (regex) location
$dewar_complete_email_locations = array('i03' => '/tray-\w+/',
);

# Industrial Contacts
# - Industrial users get a personalised email with in contact details,
# template in assets/emails/dewar-stores-in-in.html
Expand Down
3 changes: 2 additions & 1 deletion api/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ function setupApplication($mode): Slim
});

$app->get('/options', function () use ($app) {
global $motd, $authentication_type, $cas_url, $cas_sso, $package_description,
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;
Expand All @@ -76,6 +76,7 @@ function setupApplication($mode): Slim
'authentication_type' => $authentication_type,
'cas_url' => $cas_url,
'cas_sso' => $cas_sso,
'sso_url' => $sso_url,
'package_description' => $package_description,
'facility_courier_countries' => $facility_courier_countries,
'facility_courier_countries_nde' => $facility_courier_countries_nde,
Expand Down
3 changes: 2 additions & 1 deletion api/src/Authentication/AuthenticationTypeFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ class AuthenticationTypeFactory {
'dummy' => 'Dummy',
'ldap' => 'LDAP',
'simple' => 'Simple',
'oidc' => 'OIDC'
'oidc' => 'OIDC',
'combined' => 'Combined',
);

// Return instance of authentication class corresponding to $authentication_type.
Expand Down
39 changes: 39 additions & 0 deletions api/src/Authentication/Type/Combined.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace SynchWeb\Authentication\Type;

use SynchWeb\Authentication\AuthenticationInterface;
use SynchWeb\Authentication\AuthenticationParent;

/**
* Combined OIDC and CAS login to allow current api users to use the authentiate api
* endpoint with username and password
*/
class Combined extends AuthenticationParent implements AuthenticationInterface
{
private $CASAuth;
private $OIDCAuth;

function __construct() {
$this->CASAuth = new CAS();
$this->OIDCAuth = new OIDC();
}


public function authenticate($login, $password)
{
return $this->CASAuth->authenticate($login, $password);
}

public function check() {
return $this->OIDCAuth->check();
}

public function authorise() {
return $this->OIDCAuth->authorise();
}

public function authenticateByCode($code){
return $this->OIDCAuth->authenticateByCode($code);
}
}
27 changes: 15 additions & 12 deletions api/src/Authentication/Type/OIDC.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace SynchWeb\Authentication\Type;

use phpCAS;
use SynchWeb\Authentication\AuthenticationInterface;
use SynchWeb\Authentication\AuthenticationParent;
use SynchWeb\Utils;
Expand All @@ -12,16 +11,19 @@ class OIDC extends AuthenticationParent implements AuthenticationInterface
private $providerConfig = array();

function __construct() {
global $cas_url;
global $sso_url, $oidc_client_id, $oidc_client_secret;

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://' . $cas_url . '/.well-known/openid-configuration');
curl_setopt($ch, CURLOPT_URL, 'https://' . $sso_url . '/.well-known/openid-configuration');
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
curl_close($ch);

$newProviderConfig = json_decode($response);
$newProviderConfig->b64ClientCreds = base64_encode(
$oidc_client_id . ":" . $oidc_client_secret
);

if($newProviderConfig == null) {
error_log("OIDC Authentication provider replied with invalid JSON body");
Expand All @@ -32,9 +34,7 @@ function __construct() {
}

private function getUser($token)
{
global $cas_url, $cacert;

{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->providerConfig->userinfo_endpoint);
curl_setopt($ch, CURLOPT_HEADER, 0);
Expand All @@ -56,7 +56,12 @@ function authenticate($login, $password)
function check()
{
global $cookie_key;
return($this->getUser($_COOKIE[$cookie_key]));

if (array_key_exists($cookie_key, $_COOKIE)) {
return($this->getUser($_COOKIE[$cookie_key]));
}

return false;
}

function authorise()
Expand All @@ -72,21 +77,19 @@ function authorise()

function authenticateByCode($code)
{
global $cas_url, $cacert, $oidc_client_secret, $oidc_client_id, $cookie_key;
global $cacert, $oidc_client_secret, $oidc_client_id, $cookie_key;

$redirect_url = Utils::filterParamFromUrl($_SERVER["HTTP_REFERER"], "code");

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->providerConfig->token_endpoint .
'?grant_type=authorization_code&redirect_uri=' .
$redirect_url .
"&code=" . $code .
'&client_secret=' . $oidc_client_secret .
'&client_id=' . $oidc_client_id
"&code=" . $code
);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_CAINFO, $cacert);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: Basic ' . $this->providerConfig->b64ClientCreds));
$response = curl_exec($ch);
curl_close($ch);

Expand Down
51 changes: 22 additions & 29 deletions api/src/Page.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@
use ReflectionClass;
use Slim\Slim;
use SynchWeb\Database\DatabaseParent;
use xmlrpc_client;
use xmlrpcmsg;
use xmlrpcval;

use SynchWeb\Queue;
use SynchWeb\Utils;
Expand Down Expand Up @@ -948,47 +945,43 @@ function _ldap_search($search, $email = False)

# ------------------------------------------------------------------------
# Talk to channel archiver to get a pv
function _get_archive($pv, $s, $e, $n = 100)
function _get_archive($pv, $s, $e)
{
global $timezone;
global $archive_url;

$m = new xmlrpcmsg('archiver.values', array(
new xmlrpcval(1000, 'int'),
new xmlrpcval(array(new xmlrpcval($pv, 'string')), 'array'),
new xmlrpcval($s, 'int'),
new xmlrpcval(0, 'int'),
new xmlrpcval($e, 'int'),
new xmlrpcval(0, 'int'),
new xmlrpcval($n, 'int'),
new xmlrpcval(0, 'int'),
));
$c = new xmlrpc_client("/archive/cgi/ArchiveDataServer.cgi", "archiver.pri.diamond.ac.uk", 80);

$r = $c->send($m);
$val = $r->value();
if (empty($archive_url))
return array();

$parameters = array(
'pv' => $pv,
'from' => date("Y-m-d\TH:i:s", $s).'Z',
'to' => date("Y-m-d\TH:i:s", $e).'Z',
);

$ret = array();
$url_query = http_build_query($parameters);
$archive_query_url = $archive_url . "?". $url_query;
$val = file_get_contents($archive_query_url);

if ($val)
{
$str = $val->arrayMem(0);
$vals = $str->structMem('values');
$str = json_decode($val)[0];
$vals = $str->data;

$ret = array();
for ($i = 0; $i < $vals->arraySize(); $i++)
for ($i = 0; $i < sizeof($vals); $i++)
{
$vs = $vals->arrayMem($i);
$v = $vs->structMem('value')->arrayMem(0)->scalarVal();
$t = $vs->structMem('secs')->scalarVal() - 3600;

$vs = $vals[$i];
$v = $vs->val;
$t = $vs->secs - 3600;
$inputTZ = new \DateTimeZone($timezone);
$transitions = $inputTZ->getTransitions($t, $t);
if ($transitions[0]['isdst'])
$t += 3600;

array_push($ret, array($t, $v));
}

return $ret;
}
return $ret;
}


Expand Down
7 changes: 5 additions & 2 deletions api/src/Page/DC.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@ function _data_collections($single = null)
LEFT OUTER JOIN processingjob pj ON dc.datacollectionid = pj.datacollectionid
LEFT OUTER JOIN autoprocprogram app ON (app.autoprocprogramid = api.autoprocprogramid OR dc.datacollectionid = pj.datacollectionid)
INNER JOIN autoprocprogrammessage appm ON appm.autoprocprogramid = app.autoprocprogramid";
} else if ($this->arg('t') == "scrystal" || $this->arg('t') == "nscrystal") {
// Single crystal or explicitly non-single-crystal fields
$where = ($this->arg('t') == "nscrystal") ? ' AND NOT ' : ' AND ';
// This IS NOT NULL is not redundant; this condition always evalutes to TRUE with AND NOT without it
$where .= '(dcg.experimentType IS NOT NULL AND dcg.experimentType in ("OSC", "Diamond Anvil High Pressure"))';
}
}

Expand Down Expand Up @@ -986,8 +991,6 @@ function _data_collections($single = null)

if ($dc['DCT'] == 'Mesh')
$dc['DCT'] = 'Grid Scan';
if ($dc['DCT'] == 'OSC')
$dc['DCT'] = 'Data Collection';
if ($dc['DCT'] != 'Serial Fixed' && $dc['DCT'] != 'Serial Jet' && $dc['AXISRANGE'] == 0 && $dc['NI'] > 1) {
$dc['TYPE'] = 'grid';
}
Expand Down
25 changes: 9 additions & 16 deletions api/src/Page/Shipment.php
Original file line number Diff line number Diff line change
Expand Up @@ -417,9 +417,9 @@ function _get_history()
function _add_history()
{
global $in_contacts, $arrival_email;
global $dewar_complete_email; // Email list to cc if dewar back from beamline
global $dewar_complete_email, $dewar_complete_email_locations; // Email list to cc if dewar back from beamline
# Flag to indicate we should e-mail users their dewar has returned from BL
$from_beamline = False;
$send_return_email = False;

if (!$this->bcr())
$this->_error('You need to be on the internal network to add history');
Expand Down Expand Up @@ -456,16 +456,12 @@ function _add_history()
// We only add data to dewar history in lower case from this method.
// If that ever changes, update this to become case insensitive search
$last_location = $last_history['STORAGELOCATION'];

// Why don't we have beamline names in the database...?
// Currently grabbing them from the config object
// Not particularly efficient, but this is not a time critical operation so
// this approach covers all beamlines for future proofing.
// Stop/break if we find a match
$bls = $this->_get_beamlines_from_type('all');

if (in_array($last_location, $bls)) {
$from_beamline = True;
if (!isset($dewar_complete_email_locations) || !is_array($dewar_complete_email_locations)) {
$bls = $this->_get_beamlines_from_type('all');
$send_return_email = in_array($last_location, $bls);
} else if (array_key_exists($last_location, $dewar_complete_email_locations)) {
$email_location = $dewar_complete_email_locations[$last_location];
$send_return_email = preg_match($email_location, strtolower($this->arg('LOCATION')));
}
} else {
// No history - could be a new dewar, so not necessarily an error...
Expand Down Expand Up @@ -525,10 +521,7 @@ function _add_history()
$email->send($dew['LCRETEMAIL']);
}

// Change this so it checks if the boolean flag "from_beamline" is set
// The old version assumed rack-<word>-from-bl
//if (preg_match('/rack-\w+-from-bl/', strtolower($this->arg('LOCATION'))) && $dew['LCRETEMAIL']) {
if ($from_beamline && $dew['LCRETEMAIL']) {
if ($dew['LCRETEMAIL'] && $send_return_email) {
// Any data collections for this dewar's containers?
// Note this counts data collection ids for containers and uses the DataCollection.SESSIONID to determine the session/visit
// Should work for UDC (where container.sessionid is set) as well as any normal scheduled session (where container.sessionid is not set)
Expand Down
Loading

0 comments on commit 20eba26

Please sign in to comment.