Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IAM Authentication #260

Merged
merged 18 commits into from
Feb 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
a2cf6d2
Adds the option to login to GOCDB via IRIS IAM login
sarahbyrnie Sep 4, 2020
02ff875
Makes the target link uri on the landing page dynamic
sarahbyrnie Sep 4, 2020
06a1831
Adds requirement to be part of gocdb IAM group when logging in via IAM
sarahbyrnie Oct 15, 2020
d56cd7f
Automatically fills in user details from IAM token when registering a…
sarahbyrnie Oct 16, 2020
b891caa
Stops users in localAccounts group accessing site
sarahbyrnie Oct 20, 2020
09b89ce
Adds oidc authentication to the API
sarahbyrnie Nov 3, 2020
b393dcc
Removes the need for an unauthenticated token in the token class list
sarahbyrnie Nov 4, 2020
59b08ce
Checks access tokens are set being checking groups
sarahbyrnie Dec 1, 2020
6dfc916
Integrates the write API with oidc authentication and allows oidc cre…
sarahbyrnie Dec 8, 2020
75c0a89
Adds some comments and removes some unused code
sarahbyrnie Dec 8, 2020
af99f55
Update lib/Gocdb_Services/Site.php
sarahbyrnie Dec 9, 2020
2a3fc5f
Update lib/Authentication/AuthTokens/IAMAuthToken.php
sarahbyrnie Dec 9, 2020
ada3924
Update htdocs/landing/index.php
sarahbyrnie Dec 9, 2020
b11ee90
Update htdocs/web_portal/components/Get_User_Principle.php
sarahbyrnie Dec 10, 2020
c0e14ee
Update lib/Authentication/AuthTokens/IAMAuthToken.php
sarahbyrnie Dec 10, 2020
fe1a66c
Update htdocs/landing/index.php
sarahbyrnie Jan 21, 2021
e79dda7
Allows for groups claim to be a string or array depending on auth type
sarahbyrnie Feb 1, 2021
d0699aa
Re-enable shib by default, disable IAM by default
gregcorbett Feb 3, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config/gocdb_schema.xml
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,7 @@
<field>
<fname>TYPE</fname>
<length>255</length>
<regex>/^X509$/</regex>
<regex>/^(X509|OIDC Subject)$/</regex>
gregcorbett marked this conversation as resolved.
Show resolved Hide resolved
</field>
</entity>
</schema>
4 changes: 2 additions & 2 deletions htdocs/PI/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -369,8 +369,8 @@ function getXml() {

function authAnyCert() {
if (empty($this->dn))
die("<No valid certificate found. A trusted certificate is " .
"required to access this resource. Try accessing the " .
die("<No valid credentials provided. A suitable credential is " .
"required to access this resource. Try accessing this " .
"resource through the private interface.");
}

Expand Down
7 changes: 4 additions & 3 deletions htdocs/PI/write/utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,10 @@ function returnJsonWriteAPIResult ($httpResponseCode, $object) {
*/
function getAuthenticationInfo () {
require_once __DIR__ . '/../../web_portal/components/Get_User_Principle.php';
#Only x509 authentication is currently supported. If in the future we support
#API keys then I suggest we only look for a x509 DN if an API key isn't presented
$identifierType = 'X509';
#Check if associated cert/token is set to define identifier type
if(isset($_SERVER['SSL_CLIENT_CERT'])){$identifierType = 'X509';}
if(isset($_SERVER['OIDC_access_token'])){$identifierType = 'OIDC Subject';}

#This will return null if no cert is presented
$identifier = Get_User_Principle_PI();

Expand Down
23 changes: 22 additions & 1 deletion htdocs/landing/index.html → htdocs/landing/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,28 @@ <h1 class="Landing_Welcome">Welcome to GOCDB</h1>
<p>Use of GOCDB is governed by the <a class="docLink hover" href="aup.html">EGI Acceptable Use Policy</a> which places restrictions on your use of the service.</p>
<p>The <a class="docLink hover" href="privacy.html">GOCDB Privacy Notice</a> describes what personal data is collected and why, and your rights regarding this data.</p>
<p> Please read these documents before accessing GOCDB.</p>
<a href="/portal/" class="button">Access GOCDB</a>
</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
$hostname = $_SERVER['HTTP_HOST'];
$egi_target = urlencode("https://" . $hostname . "/portal/");
$egi_redirect = "https://" . $hostname . "/Shibboleth.sso/Login?target=" . $egi_target;
if($_SERVER['REQUEST_URI'] === "/"){
$iam_target = "target_link_uri=" . urlencode("https://" . $hostname . "/portal/");
}
else{
$iam_target=ltrim($_SERVER['REQUEST_URI'], '/?');
}
$iris_url = urlencode("https://iris-iam.stfc.ac.uk/");
$iam_redirect = "https://" . $hostname . "/portal/redirect_uri?iss=" . $iris_url . "&" . $iam_target;
?>
<a style="width:30%; display:inline-block; font-size:1.5em" href="<?php echo $egi_redirect; ?>" class="button">EGI Check-In</a>
<a style="width:30%; display:inline-block; font-size:1.5em" href="<?php echo $iam_redirect ?>" class="button">IRIS IAM</a>
</div>
<p>Browse the <a href="https://wiki.egi.eu/wiki/GOCDB" class="docLink hover">GOCDB documentation index</a> on the EGI wiki.</p>
</div>

Expand Down
14 changes: 11 additions & 3 deletions htdocs/web_portal/components/Get_User_Principle.php
Original file line number Diff line number Diff line change
Expand Up @@ -162,21 +162,29 @@ function Get_User_Principle(){
}

/**
* Get the DN from an x509 cert or null if a user certificate can't be loaded.
* Called from the PI to authenticate requests using certificates only.
* Get the DN from an x509 cert, Principle from oidc token, or null if neither can be loaded.
* Called from the PI to authenticate requests using certificates or oidc.
* @return string or null if can't authenticate request
*/
function Get_User_Principle_PI() {
$fwMan = \org\gocdb\security\authentication\FirewallComponentManager::getInstance();
$firewallArray = $fwMan->getFirewallArray();
try {
try{
$x509Token = new org\gocdb\security\authentication\X509AuthenticationToken();
$auth = $firewallArray['fwC1']->authenticate($x509Token);
return $auth->getPrinciple();
} catch(org\gocdb\security\authentication\AuthenticationException $ex){
// failed auth, so attempt OIDC auth
try{
$token = new org\gocdb\security\authentication\IAMAuthToken();
$auth = $firewallArray['fwC1']->authenticate($token);
return $auth->getPrinciple();
} catch(org\gocdb\security\authentication\AuthenticationException $ex){
// failed auth, so return null and let calling page decide to allow
// access or not (some PI methods don't need to be authenticated with a cert)
}
}

return null;
}

Expand Down
1 change: 1 addition & 0 deletions htdocs/web_portal/controllers/site/add_api_auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ function draw(\User $user = null, \Site $site = null) {
$params['site'] = $site;
$params['authTypes'] = array();
$params['authTypes'][]='X509';
$params['authTypes'][]='OIDC Subject';

show_view("site/add_api_auth.php", $params);
die();
Expand Down
1 change: 1 addition & 0 deletions htdocs/web_portal/controllers/site/edit_api_auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ function draw(\User $user = null, \APIAuthentication $authEnt = null, \Site $sit
$params['authEnt'] = $authEnt;
$params['authTypes'] = array();
$params['authTypes'][]='X509';
$params['authTypes'][]='OIDC Subject';

show_view("site/edit_api_auth.php", $params);
die();
Expand Down
12 changes: 11 additions & 1 deletion htdocs/web_portal/controllers/user/register.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,20 @@ function draw() {
die();
}

//Extract users email from oidc claims
$authDetails = $_SERVER['OIDC_CLAIM_external_authn'];
gregcorbett marked this conversation as resolved.
Show resolved Hide resolved
$startPos = 3+strpos($authDetails, ":", (strpos($authDetails, "MAIL")));
$endPos = strpos($authDetails, "\"", 3+$startPos);
$length = $endPos-$startPos;
$userEmail = substr($authDetails, $startPos, $length);

/* @var $authToken \org\gocdb\security\authentication\IAuthentication */
$authToken = Get_User_AuthToken();
$params['authAttributes'] = $authToken->getDetails();

$params['given_name'] = $_SERVER['OIDC_CLAIM_given_name'];
gregcorbett marked this conversation as resolved.
Show resolved Hide resolved
$params['family_name'] = $_SERVER['OIDC_CLAIM_family_name'];
$params['email'] = $userEmail;
$params['dn'] = $dn;
show_view('user/register.php', $params);
}
Expand Down Expand Up @@ -91,4 +101,4 @@ function submit() {
}
}

?>
?>
2 changes: 1 addition & 1 deletion htdocs/web_portal/views/site/add_api_auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<b>Caution: it is possible to delete information using the write functionality of the API.</b>
<br/>
<form class="inputForm" method="post" action="index.php?Page_Type=Add_API_Authentication_Entity&parentid=<?php echo($params['site']->getId());?>" name="addAPIAuthenticationEntity">
<span class="input_name">Identifier (e.g. Certificate DN)*</span>
<span class="input_name">Identifier (e.g. Certificate DN or OIDC Subject)*</span>
<input type="text" value="" name="IDENTIFIER" class="input_input_text">
<br />
<span class="input_name">Credential type*</span>
Expand Down
2 changes: 1 addition & 1 deletion htdocs/web_portal/views/site/edit_api_auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<h1>Edit API credential for <?php xecho($params['site']->getName());?></h1>
<br />
<form class="inputForm" method="post" action="index.php?Page_Type=Edit_API_Authentication_Entity&parentid=<?php echo($params['site']->getId())?>&authentityid=<?php echo($params['authEnt']->getId())?>" name="addAPIAuthenticationEntity">
<span class="input_name">Identifier (e.g. Certificate DN)*</span>
<span class="input_name">Identifier (e.g. Certificate DN or OIDC Subject)*</span>
<input type="text" value="<?php xecho($params['authEnt']->getIdentifier()) ?>" name="IDENTIFIER" class="input_input_text">
<br />
<span class="input_name">Credential type*</span>
Expand Down
6 changes: 3 additions & 3 deletions htdocs/web_portal/views/user/register.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,19 @@
Forename *
<span class="input_syntax" >(unaccentuated letters, spaces, dashes and quotes)</span>
</span>
<input class="input_input_text" type="text" name="FORENAME" />
<input class="input_input_text" type="text" name="FORENAME" value="<?php xecho($params['given_name']) ?>" />

<span class="input_name">
Surname *
<span class="input_syntax" >(unaccentuated letters, spaces, dashes and quotes)</span>
</span>
<input class="input_input_text" type="text" name="SURNAME" />
<input class="input_input_text" type="text" name="SURNAME" value="<?php xecho($params['family_name']) ?>" />

<span class="input_name">
E-Mail *
<span class="input_syntax" >(valid e-mail format)</span>
</span>
<input class="input_input_text" type="text" name="EMAIL" />
<input class="input_input_text" type="text" name="EMAIL" value="<?php xecho($params['email']) ?>" />

<span class="input_name">
Telephone Number
Expand Down
3 changes: 3 additions & 0 deletions lib/Authentication/AuthProviders/GOCDBAuthProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ public function authenticate(IAuthentication $auth){
else if($auth instanceof SimpleSamlPhpAuthToken){
$roles[] = 'ROLE_SAMLUSER';
}
else if($auth instanceof IAMAuthToken){
$roles[] = 'ROLE_IRISUSER';
}
$auth->setAuthorities($roles);
return $auth;
}
Expand Down
132 changes: 132 additions & 0 deletions lib/Authentication/AuthTokens/IAMAuthToken.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<?php
namespace org\gocdb\security\authentication;
require_once __DIR__.'/../IAuthentication.php';

/*
* Copyright (C) 2015 STFC
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* AuthToken for use with IRIS IAM.
*
* @see IAuthentication
* @author Sarah Byrne
*/
class IAMAuthToken implements IAuthentication {

private $userDetails = null;
private $authorities = array();
private $principal;

public function __construct() {
$this->getAttributesInitToken();
}

/**
* {@see IAuthentication::eraseCredentials()}
*/
public function eraseCredentials() {

}

/**
* {@see IAuthentication::getAuthorities()}
*/
public function getAuthorities() {
return $this->authorities;
}

/**
* {@see IAuthentication::getCredentials()}
* @return string An empty string as passwords are not used by this token.
*/
public function getCredentials() {
return ""; // none used in this token, handled by SSO/SAML
}

/**
* A custom object used to store additional user details.
* Allows non-security related user information (such as email addresses,
* telephone numbers etc) to be stored in a convenient location.
* {@see IAuthentication::getDetails()}
*
* @return Object or null if not used
*/
public function getDetails() {
return $this->userDetails;
}

/**
* {@see IAuthentication::getPrinciple()}
* @return string unique principle string of user
*/
public function getPrinciple() {
return $this->principal;
}



private function getAttributesInitToken(){
if(isset($_SERVER['OIDC_access_token'])){
$this->principal = $_SERVER["REMOTE_USER"];
$this->userDetails = array('AuthenticationRealm' => array('IRIS IAM - OIDC'));
//Don't allow access if user only has a local account on IRIS
if(strpos($_SERVER['OIDC_CLAIM_groups'], "localAccounts")===false){
}else{
die('You must login via your organisation on IRIS IAM to gain access to this site.');
}
//Don't allow access unless user is a member of the IRIS gocdb group
if(strpos($_SERVER['OIDC_CLAIM_groups'], "gocdb")===false and in_array('gocdb', $_SERVER['OIDC_CLAIM_groups'])===false){
die('You do not belong to the correct group to gain access to this site. Please visit iris-iam.stfc.ac.uk and submit a request to join the GOCDB group. This shall be reviewed by a GOCDB admin.');
}
}
}

/**
* {@see IAuthentication::setAuthorities($authorities)}
*/
public function setAuthorities($authorities) {
$this->authorities = $authorities;
}

/**
* {@see IAuthentication::setDetails($userDetails)}
* @param Object $userDetails
*/
public function setDetails($userDetails) {
$this->userDetails = $userDetails;
}

/**
* {@see IAuthentication::validate()}
*/
public function validate() {

}

/**
* {@see IAuthentication::isPreAuthenticating()}
*/
public static function isPreAuthenticating() {
return true;
}

/**
* Returns true, this token reads the ShibSP session attributes and so
* does not need to be stateful itself.
* {@see IAuthentication::isStateless()}
*/
public static function isStateless() {
return true;
}

}
9 changes: 0 additions & 9 deletions lib/Authentication/AuthTokens/ShibAuthToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,15 +166,6 @@ private function getAttributesInitToken(){
$this->userDetails = array('AuthenticationRealm' => array('EGI Proxy IdP'));
return;
}


// else {
// die('Now go configure this AuthToken file ['.__FILE__.']');
// }
// if we have not set the principle/userDetails, re-direct to our Discovery Service
$target = urlencode("https://" . $hostname . "/portal/");
header("Location: https://" . $hostname . "/Shibboleth.sso/Login?target=" . $target);
die();
}

/**
Expand Down
1 change: 1 addition & 0 deletions lib/Authentication/MyConfig1.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ function __construct() {

$this->tokenClassList = array();
$this->tokenClassList[] = 'org\gocdb\security\authentication\X509AuthenticationToken';
//$this->tokenClassList[] = 'org\gocdb\security\authentication\IAMAuthToken';
$this->tokenClassList[] = 'org\gocdb\security\authentication\ShibAuthToken';
//$this->tokenClassList[] = 'org\gocdb\security\authentication\SimpleSamlPhpAuthToken';
//$this->tokenClassList[] = 'org\gocdb\security\authentication\UsernamePasswordAuthenticationToken';
Expand Down
10 changes: 10 additions & 0 deletions lib/Gocdb_Services/Site.php
Original file line number Diff line number Diff line change
Expand Up @@ -1408,6 +1408,11 @@ public function addAPIAuthEntity(\Site $site, \User $user, $newValues) {
if ($type == 'X509' && !preg_match("/^(\/[A-Za-z]+=[a-zA-Z0-9\/\-\_\s\.,'@:\/]+)*$/", $identifier)) {
throw new \Exception("Invalid x509 DN");
}

//If the entity is of type OIDC subject, do a more thorough check again
if ($type == 'OIDC Subject' && !preg_match("/^([a-f0-9]{8}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{12})$/", $identifier)) {
throw new \Exception("Invalid OIDC Subject");
}

//Check there isn't already a identifier of that type with that identifier for that Site
$this->uniqueAPIAuthEnt($site, $identifier, $type);
Expand Down Expand Up @@ -1488,6 +1493,11 @@ public function editAPIAuthEntity(\APIAuthentication $authEntity, \User $user, $
throw new \Exception("Invalid x509 DN");
}

//If the entity is of type OIDC subject, do a more thorough check again
if ($type == 'OIDC Subject' && !preg_match("/^([a-z0-9]{8}\-[a-z0-9]{4}\-[a-z0-9]{4}\-[a-z0-9]{4}\-[a-z0-9]{12})$/", $identifier)) {
throw new \Exception("Invalid OIDC Subject");
}

/**
* As long as something has changed, check there isn't already a
* identifier of that type with that identifier for that Site
Expand Down