Skip to content

Commit

Permalink
Add code to support admin ONLY x509 login for the portal
Browse files Browse the repository at this point in the history
  • Loading branch information
Sae126V committed Nov 13, 2024
1 parent ebbb7e2 commit d76dcf0
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 37 deletions.
4 changes: 4 additions & 0 deletions config/local_info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,10 @@
-->
<restrict_personal_data>false</restrict_personal_data>

<igtf>
<admin_only>true</admin_only>
</igtf>

</local_info>

<!--
Expand Down
7 changes: 7 additions & 0 deletions config/local_info.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,13 @@
</xs:complexType>
</xs:element>
<xs:element name="send_email" type="xs:boolean" minOccurs="0"/>
<xs:element name="igtf">
<xs:complexType>
<xs:all>
<xs:element name="admin_only" type="xs:boolean" minOccurs="1"/>
</xs:all>
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="url" type="xs:anyURI"/>
</xs:complexType>
Expand Down
25 changes: 23 additions & 2 deletions htdocs/landing/index.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,27 @@
<?php
if(session_start() === PHP_SESSION_NONE) {
session_start();
}

// Check if SSL client verification is successful
$sslClientVerify = isset($_SERVER['SSL_CLIENT_VERIFY'])
? $_SERVER['SSL_CLIENT_VERIFY']
: 'NONE';

$pathName = isset($_SERVER['REQUEST_URI'])
? $_SERVER['REQUEST_URI']
: '/';

if (
$sslClientVerify === 'SUCCESS'
&& empty($_SESSION['SSL-Retry_login'])
&& $pathName === "/"
) {
// Redirect the user to the /portal from the root URL.
header("Location: /portal");
die();
}

require_once __DIR__.'/../../lib/Gocdb_Services/Factory.php';
$configServ = \Factory::getConfigService();
$configServ->setLocalInfoOverride($_SERVER['SERVER_NAME']);
Expand Down Expand Up @@ -39,8 +62,6 @@
?>
</div>
<div style="width: 80%; margin-left: auto; margin-right: auto;">
<a href="/portal/" style="width:68%; font-size:1.7em" class="button">Access GOCDB using your IGTF X.509 Certificate</a>
<p>or</p>
<p>Access GOCDB using one of the following:</p>
<div>
<?php
Expand Down
119 changes: 84 additions & 35 deletions htdocs/web_portal/components/Get_User_Principle.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,15 @@ function Get_User_AuthToken(){
/* @var $firewall \org\gocdb\security\authentication\IFirewallComponent */
$firewall = $firewallArray['fwC1']; // select which firewall component you need
$auth = $firewall->getAuthentication(); // invoke token resolution process

if ($auth != null) {
$principleString = $auth->getPrinciple();
// update the static holder so we can quickly return the token
// for the current request on repeat callouts to Get_User_AuthToken (is quicker than authenticating again).
MyStaticPrincipleHolder::getInstance()->setPrincipleString($principleString);
MyStaticAuthTokenHolder::getInstance()->setAuthToken($auth);
return $auth;

$authToken = validateRequest($auth, $principleString, true);

if ($authToken !== null) {
return $authToken;
}
}

// We don't want the portal to be exposed without authentication (even
Expand Down Expand Up @@ -160,42 +162,24 @@ function Get_User_Principle(){
/* @var $firewall \org\gocdb\security\authentication\IFirewallComponent */
$firewall = $firewallArray['fwC1']; // select which firewall component you need
$auth = $firewall->getAuthentication(); // invoke token resolution process
if ($auth != null) {

if ($auth !== null) {
$principleString = $auth->getPrinciple();
// update the static holder so we can quickly return the principle
// for the current request on repeat callouts to Get_User_Principle (is quicker than authenticating again).
MyStaticPrincipleHolder::getInstance()->setPrincipleString($principleString);
MyStaticAuthTokenHolder::getInstance()->setAuthToken($auth);

$serv = \Factory::getUserService();

// Get user by searching user identifiers
$user = $serv->getUserByPrinciple($principleString);

// If cannot find user, search certificate DNs instead
if ($user === null) {
$user = $serv->getUserByCertificateDn($principleString);
$authExists = False;
} else {
$authExists = True;
}

// Is user registered/known in the DB? if true, update their last login time
// once for the current request.
if ($user !== null) {
$serv->updateLastLoginTime($user);
$authUserPrinciple = validateRequest($auth, $principleString, false);

// If identifier for current auth does not exist, add to user
if (!$authExists) {
// Get type of auth logged in with e.g. X.509)
$authType = $auth->getDetails()['AuthenticationRealm'][0];
$identifierArr = array($authType, $principleString);
$serv->migrateUserCredentials($user, $identifierArr, $user);
}
if ($authUserPrinciple !== null) {
return $authUserPrinciple;
}
return $principleString;
}

if(session_start() === PHP_SESSION_NONE) {
session_start();
}

// `SSL-Retry_login` is required to end the recursive calls to /portal.
$_SESSION['SSL-Retry_login'] = true;

// We don't want the portal to be exposed without authentication (even
// though no actual info is displayed to an unauthenticated user),
// so if we have not set the principle/userDetails,
Expand Down Expand Up @@ -243,4 +227,69 @@ function redirectUserToDiscoveryPage()
die();
}

/**
* Helper method to return the user principle string or authToken, if allowed.
*
* The authentication token object.
* @param $auth \org\gocdb\security\authentication\IAuthenticationToken
*
* The user's principle string (X.509 DN or SAML attribute).
* @param $principleString string
*
* If `$needAuthTokenOnly` is set to `true` -> It returns authToken
* @param $needAuthTokenOnly bool
*
* The user's principle string or
* The IAuthenticationToken for the user or
* NULL if processing fails.
* @return string|\org\gocdb\security\authentication\IAuthenticationToken|null
*/
function validateRequest($auth, $principleString, $needAuthTokenOnly)
{
$serv = \Factory::getUserService();

// Get user by searching user identifiers
$user = $serv->getUserByPrinciple($principleString);

// Get type of auth logged in with (e.g., X.509)
$authType = $auth->getDetails()['AuthenticationRealm'][0];

// Admin's are allowed to use IGTF ?
$canAdminAccessUsingIGTF = \Factory::getConfigService()->isAdminAllowedToUseIGTF();

/**
* Check if user exists and is either an admin who is allowed to use IGTF
* or user is NOT using X.509 authentication.
*/
if (!is_null($user)) {
if (
($canAdminAccessUsingIGTF && $user->isAdmin())
|| $authType !== 'X.509'
) {
/**
* Update the static holder with the principle string
* and auth token for quick retrieval.
*/
MyStaticPrincipleHolder::getInstance()->setPrincipleString(
$principleString
);
MyStaticAuthTokenHolder::getInstance()->setAuthToken($auth);

if ($needAuthTokenOnly) {
return $auth;
}

/**
* If the user is registered/known in the DB,
* update their last login time.
*/
$serv->updateLastLoginTime($user);

return $principleString;
}
}

return null;
}

?>
9 changes: 9 additions & 0 deletions lib/Gocdb_Services/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -567,4 +567,13 @@ public function getEmailTo()

return $emailTo;
}

public function isAdminAllowedToUseIGTF()
{
if (strtolower( $this->GetLocalInfoXML()->igtf->admin_only) === 'true') {
return true;
}

return false;
}
}

0 comments on commit d76dcf0

Please sign in to comment.