diff --git a/INSTALL.md b/INSTALL.md index 48b5eba08..174f9baab 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -22,7 +22,7 @@ This file is best viewed using a browser-plugin for markdown `.md` files. * [Apache Http](#apache-and-x509-host-cert) * Version 2.2 or higher with `mod_ssl` module - * X509 host certificate. + * X.509 host certificate. * [Database server](#database-server) * Oracle 11g+ or MariaDB/MySQL @@ -108,7 +108,7 @@ update your php.ini by adding `extension=[php_]timezonedb.so|dll` (note, Win pre * All dates are stored as UTC in the DB and converted from local timezones. * Do not forget to configure your timezone settings correctly. -### Apache and x509 Host cert +### Apache and X.509 Host cert A sample Apache config file is provided `config/gocdbssl.conf`. This file defines a sample apache virtual host for serving your GocDB portal, including URL mappings/aliases and SSL settings. @@ -557,7 +557,7 @@ and editing which URL page mappings use the `rejectIfNotAuthenticated()` invocat ### Authentication Authentication is handled by the `lib/Authentication` package, and is configured -for x509 client certificate authentication by default. Different authentication +for X.509 client certificate authentication by default. Different authentication schemes can be configured using the abstractions in this package such as SAML2 for integration with Federated Identity Management. See `lib/Authentication/README.md` for details. diff --git a/config/gocdb_schema.xml b/config/gocdb_schema.xml index 3077c58c2..18d4ec715 100644 --- a/config/gocdb_schema.xml +++ b/config/gocdb_schema.xml @@ -604,7 +604,7 @@ TYPE 255 - /^(X509|OIDC Subject)$/ + /^(X\.509|OIDC Subject)$/ ALLOW_WRITE diff --git a/htdocs/PI/index.php b/htdocs/PI/index.php index 2aa31e9c9..ce480cf2b 100644 --- a/htdocs/PI/index.php +++ b/htdocs/PI/index.php @@ -390,7 +390,7 @@ function authByCert() { // Check if it is registered API Authentication credential. $authEntServ = \Factory::getAPIAuthenticationService(); - $authEnt = $authEntServ->getAPIAuthentication($this->dn, "X509"); + $authEnt = $authEntServ->getAPIAuthentication($this->dn, "X.509"); if (!is_null($authEnt)) { $authEntServ->updateLastUseTime($authEnt); diff --git a/htdocs/PI/write/PIWriteRequest.php b/htdocs/PI/write/PIWriteRequest.php index a4d325b56..0c2c140cd 100644 --- a/htdocs/PI/write/PIWriteRequest.php +++ b/htdocs/PI/write/PIWriteRequest.php @@ -118,7 +118,7 @@ public function __construct() { * @param string $requestUrl url used to access API, only the last section * @param string|null $requestContents contents of the request (JSON String or null) * @param Site $siteService Site Service - * @param array ('userIdentifier'=>,'userIdentifierType'=>) + * @param array ('userIdentifier'=>,'userIdentifierType'=>) * @return array ('httpResponseCode'=>,'returnObject'=>) */ public function processRequest($method, $requestUrl, $requestContents, Site $siteService, $authArray) { @@ -620,10 +620,10 @@ private function setAuthInfo($authArray) { */ private function checkUserAuthenticated () { if (empty($this->userIdentifier)) { - #yes 403 - 401 is not appropriate for X509 authentication + #yes 403 - 401 is not appropriate for X.509 authentication $this->exceptionWithResponseCode(403, "You need to be authenticated to access this resource. " . - "Please provide a valid IGTF X509 Certificate" + "Please provide a valid IGTF X.509 Certificate" ); } } @@ -632,7 +632,7 @@ private function checkAuthorisation (Site $siteService, \Site $site, $identifier try { $siteService->checkAuthorisedAPIIdentifier($site, $identifier, $indentifierType); } catch (\Exception $e) { - #yes 403 - 401 is not appropriate for X509 authentication + #yes 403 - 401 is not appropriate for X.509 authentication $this->httpResponseCode = 403; throw $e; } diff --git a/htdocs/PI/write/utils.php b/htdocs/PI/write/utils.php index 9c96299e3..b69da4a44 100644 --- a/htdocs/PI/write/utils.php +++ b/htdocs/PI/write/utils.php @@ -52,7 +52,7 @@ function returnJsonWriteAPIResult ($httpResponseCode, $object) { function getAuthenticationInfo () { require_once __DIR__ . '/../../web_portal/components/Get_User_Principle.php'; #Check if associated cert/token is set to define identifier type - if(isset($_SERVER['SSL_CLIENT_CERT'])){$identifierType = 'X509';} + if(isset($_SERVER['SSL_CLIENT_CERT'])){$identifierType = 'X.509';} if(isset($_SERVER['OIDC_access_token'])){$identifierType = 'OIDC Subject';} #This will return null if no cert is presented diff --git a/htdocs/landing/authenticationError.html b/htdocs/landing/authenticationError.html deleted file mode 100644 index db2d0b98c..000000000 --- a/htdocs/landing/authenticationError.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - To access this page, you require an X509 digital certificate installed in your browser that has been - issued by one of the recognised EU-Grid-PMA Certification Authorities. -
-
- -
- Please note, after you have installed your certificate, you will need to restart and refresh your browser - to re-establish the secure connection. -
- - - - - - diff --git a/htdocs/web_portal/components/Get_User_Principle.php b/htdocs/web_portal/components/Get_User_Principle.php index 0a3509412..78c79e361 100644 --- a/htdocs/web_portal/components/Get_User_Principle.php +++ b/htdocs/web_portal/components/Get_User_Principle.php @@ -4,7 +4,7 @@ * File: Get_User_Principle.php * Author: David Meredith * Description: Returns the user's principle ID string or AuthToken for the user that's currently - * connected (for x509 this is a DN). + * connected (for X.509 this is a DN). * * License information * @@ -137,7 +137,7 @@ function Get_User_AuthType() { } /** - * Get the user's principle string (x509 DN from certificate or from SAML attribute). + * Get the user's principle string (X.509 DN from certificate or from SAML attribute). *

* Called from the portal to allow authentication. * This method serves as the global integration point for all authentication requests. @@ -204,7 +204,7 @@ function Get_User_Principle(){ } /** - * Get the DN from an x509 cert, Principle from oidc token, or null if neither can be loaded. + * Get the DN from an X.509 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 */ @@ -243,77 +243,4 @@ function redirectUserToDiscoveryPage() die(); } - - -/*function Get_User_Principle_back() -{ - // Return hard wired user's principle string (DN) e.g. for testing - // ======================================================= - //return '/C=UK/O=eScience/OU=CLRC/L=DL/CN=david meredith'; - - // Check if an authentication token has been set in the SecurityContext class - // by higher level code, eg Symfony Security which provides a Firewall component - // may have been used to intercept the HTTP request and authenticate the - // user (using whatever auth scheme was configured in the Firewall). A - // Symfony controller can then subsequently set the token in the SecurityContext - // before invoking the GOCDB code. - // ======================================================= - require_once __DIR__.'/../../../lib/Gocdb_Services/SecurityContextSource.php'; - if(\SecurityContextSource::getContext() != null){ - $token = \SecurityContextSource::getContext()->getToken(); - return str_replace("emailAddress=", "Email=", $token->getUser()->getUserName()); - } - - // ================Use x509 Authentication======================= - //if(!isset($_SERVER['SSL_CLIENT_CERT'])) - // return ""; - //$Raw_Client_Certificate = $_SERVER['SSL_CLIENT_CERT']; - //$Plain_Client_Cerfificate = openssl_x509_parse($Raw_Client_Certificate); - //$User_DN = $Plain_Client_Cerfificate['name']; - // harmonise display of the "email" field that can be different depending on - // used version of SSL - //$User_DN = str_replace("emailAddress=", "Email=", $User_DN); - //return $User_DN; - if (isset($_SERVER['SSL_CLIENT_CERT'])) { - $Raw_Client_Certificate = $_SERVER['SSL_CLIENT_CERT']; - if (isset($Raw_Client_Certificate)) { - $Plain_Client_Cerfificate = openssl_x509_parse($Raw_Client_Certificate); - $User_DN = $Plain_Client_Cerfificate['name']; - if (isset($User_DN)) { - // harmonise "email" field that can be different depending on version of SSL - $dn = str_replace("emailAddress=", "Email=", $User_DN); - if ($dn != null && $dn != '') { - return $dn; - } - } - } - } - - - // Fall back to try saml authentication (simplesaml) - // ======================================================= - if(false){ // disable by default - to use saml requires install of simplesamlphp and config below - require_once('/var/simplesamlphp/lib/_autoload.php'); - $as = new SimpleSAML_Auth_Simple('default-sp'); - $as->requireAuth(); - \Factory::$properties['LOGOUTURL'] = $as->getLogoutURL('https://gocdb-test.esc.rl.ac.uk'); - $attributes = $as->getAttributes(); - if(!empty($attributes)){ - //return $attributes['eduPersonPrincipalName'][0]; - $dnAttribute = $attributes['urn:oid:1.3.6.1.4.1.11433.2.2.1.9'][0]; - if(!empty($dnAttribute)){ - return str_replace("emailAddress=", "Email=", $dnAttribute); - } else { - die('Did not retrieve a valid certificate DN from identify provider - your SSO ' - . 'account needs to be associated with a certificate to login via this route'); - } - } - } - - // Couldn't authetnicate the user, so finally return null - return null; -}*/ - - - ?> diff --git a/htdocs/web_portal/controllers/site/add_api_auth.php b/htdocs/web_portal/controllers/site/add_api_auth.php index b718b427a..6a176682f 100644 --- a/htdocs/web_portal/controllers/site/add_api_auth.php +++ b/htdocs/web_portal/controllers/site/add_api_auth.php @@ -58,7 +58,7 @@ function draw(\User $user = null, \Site $site = null) { $params['site'] = $site; $params['authTypes'] = array(); - $params['authTypes'][]='X509'; + $params['authTypes'][]='X.509'; $params['authTypes'][]='OIDC Subject'; $params['user'] = $user; $params['allowWrite'] = false; diff --git a/htdocs/web_portal/controllers/site/edit_api_auth.php b/htdocs/web_portal/controllers/site/edit_api_auth.php index e75a2cfec..e84c1b451 100644 --- a/htdocs/web_portal/controllers/site/edit_api_auth.php +++ b/htdocs/web_portal/controllers/site/edit_api_auth.php @@ -66,7 +66,7 @@ function draw(\User $user = null, \APIAuthentication $authEnt = null, \Site $sit $params['site'] = $site; $params['authEnt'] = $authEnt; $params['authTypes'] = array(); - $params['authTypes'][]='X509'; + $params['authTypes'][]='X.509'; $params['authTypes'][]='OIDC Subject'; $params['user'] = $user; diff --git a/lib/Authentication/AuthProviders/GOCDBAuthProvider.php b/lib/Authentication/AuthProviders/GOCDBAuthProvider.php index d67cb7c73..ab37d65e8 100644 --- a/lib/Authentication/AuthProviders/GOCDBAuthProvider.php +++ b/lib/Authentication/AuthProviders/GOCDBAuthProvider.php @@ -77,7 +77,7 @@ private function authenticateAgainstDB($auth){ // between the returned $userDetails object and the given $auth token. // Note, getPassword() never returns null, even for auth mechanisms that // don't use a password in which case an empty string is returned. This - // allows the same auth logic across different mechanisms (e.g. x509). + // allows the same auth logic across different mechanisms (e.g. X.509). if($userDetails->getUsername() == $auth->getPrinciple() && $userDetails->getPassword() == $auth->getCredentials()){ diff --git a/lib/Authentication/AuthTokens/X509AuthenticationToken.php b/lib/Authentication/AuthTokens/X509AuthenticationToken.php index 7329647c2..3b5aa3a4f 100644 --- a/lib/Authentication/AuthTokens/X509AuthenticationToken.php +++ b/lib/Authentication/AuthTokens/X509AuthenticationToken.php @@ -7,7 +7,7 @@ //use Monolog\Handler\StreamHandler; /** - * An implementation of IAuthentication for use with X509 certificates. + * An implementation of IAuthentication for use with X.509 certificates. * * @see IAuthentication * @author David Meredith @@ -21,10 +21,6 @@ class X509AuthenticationToken implements IAuthentication { //private $logger; public function __construct() { - // create logger - //$this->logger = new Logger('X509AuthenticationTokenLogger'); - //$this->logger->pushHandler(new StreamHandler(__DIR__.'/../../../gocdb.log', Logger::DEBUG)); - $this->initialDN = $this->getDN(); $this->userDetails = array('AuthenticationRealm' => array('X.509')); } @@ -45,7 +41,7 @@ public static function isPreAuthenticating() { /** * {@see IAuthentication::getCredentials()} - * @return string An empty string as passwords are not used in X509. + * @return string An empty string as passwords are not used in X.509. */ public function getCredentials() { return ""; @@ -53,10 +49,10 @@ public function getCredentials() { /** * {@see IAuthentication::eraseCredentials()} - * Does nothing, passwords not ussed in X509. + * Does nothing, passwords not ussed in X.509. */ public function eraseCredentials() { - // do nothing, password not used for X509 + // do nothing, password not used for X.509 } /** @@ -153,4 +149,3 @@ public function setAuthorities($authorities) { } - diff --git a/lib/Authentication/IAuthentication.php b/lib/Authentication/IAuthentication.php index 1fc72332c..141f7473e 100644 --- a/lib/Authentication/IAuthentication.php +++ b/lib/Authentication/IAuthentication.php @@ -33,7 +33,7 @@ public static function isStateless(); * resolution process for automatic submission to * AuthenticationManager.authenticate(Authentication). *

- * X509 is an example of a pre-authentication token - the server establishes + * X.509 is an example of a pre-authentication token - the server establishes * that the user has provided a valid and trustworthy certificate before * reaching the underlying app (which means the token can be automatically * created during token resolution and authenticated). @@ -50,7 +50,7 @@ public static function isPreAuthenticating(); * The identity of the principal being authenticated. * Note, this will vary according to differet authentication mechansisms. * In the case of an authentication request (IAuthenticationManager.authentication($authToken)) - * with username and password, this would be the username. For X509 + * with username and password, this would be the username. For X.509 * it would be the certificate DN. Callers are expected to populate the * principal for an authentication request (IAuthenticationManager.authentication($authToken)). *

@@ -65,7 +65,7 @@ public function getPrinciple(); /** * Get current principal's credentials (usually a password). Never null. When a password is not - * used for the chosen auth scheme (e.g. X509), return an empty string. + * used for the chosen auth scheme (e.g. X.509), return an empty string. * @return object never null */ public function getCredentials(); @@ -113,7 +113,7 @@ public function setAuthorities($authorities); * Implementations MUST throw an AuthenticationException if the token's internal state becomes * invalid due to whatever change (required since instances are mutable). *

- * For example, in the case of a cached x509 token, the client may freely change + * For example, in the case of a cached X.509 token, the client may freely change * their certificate in their browser by clearing the browser ssl * cache and refreshing the page. In this case, the DN may change from the * initial DN used when constructing the token. diff --git a/lib/Authentication/IUserDetailsService.php b/lib/Authentication/IUserDetailsService.php index 6f780efa6..b02adce2f 100644 --- a/lib/Authentication/IUserDetailsService.php +++ b/lib/Authentication/IUserDetailsService.php @@ -12,7 +12,7 @@ interface IUserDetailsService { /** * Locates the user based on the given username string. * The username string must uniquely identify the user (its format can differ - * depending on the authentication mechanism e.g. could be a DN string for x509). + * depending on the authentication mechanism e.g. could be a DN string for X.509). * * @param string $username the user string identifying the user whose data is required. * @return IUserDetails implementation (never null) diff --git a/lib/Authentication/README.md b/lib/Authentication/README.md index 215398186..9a62c5e88 100644 --- a/lib/Authentication/README.md +++ b/lib/Authentication/README.md @@ -2,239 +2,239 @@ Authentication Abstraction Framework =================================== This file is best viewed using a browser-plugin for markdown `.md` files. -This Authentication package/framework provides generic abstractions and some selected -implementations to support different authentication mechanisms such as x509, -SAML and un/pw authentication. It is reusable in other php projects. All objects are defined within a namespace -to prevent collision with other components. +This Authentication package/framework provides generic abstractions and some selected +implementations to support different authentication mechanisms such as X.509, +SAML and un/pw authentication. It is reusable in other php projects. All objects are defined within a namespace +to prevent collision with other components. -* Without modification, the framework is configured for x509 client certificate authentication. -Therefore, with a default installation, you will need to configure your Apache +* Without modification, the framework is configured for X.509 client certificate authentication. +Therefore, with a default installation, you will need to configure your Apache instance for SSL for client cert authentication. -Please note, it will no doubt need to be extended and modified to suit the -requirements of the particular deployment. The authentication abstractions can't be used -'out of the box' without some integration/dev work to cater for your +Please note, it will no doubt need to be extended and modified to suit the +requirements of the particular deployment. The authentication abstractions can't be used +'out of the box' without some integration/dev work to cater for your particular local credential store and the required auth-mechanisms. - + Inspired by [Spring Security 3 framework](http://static.springsource.org/spring-security) -WARNING: This package is NO WAY a complete re-implementation for php, rather it is -a rather naive micro-uber-simplification! -There is plenty of scope to further develop this module to support 'out of the box' -deployment for different auth mechanisms. +WARNING: This package is NO WAY a complete re-implementation for php, rather it is +a rather naive micro-uber-simplification! +There is plenty of scope to further develop this module to support 'out of the box' +deployment for different auth mechanisms. -###Summary - How does the framework authenticates a user? +###Summary - How does the framework authenticates a user? * Client code uses the `FirewallComponentManager.php` instance to create/return -the required `IFirewallComponent.php` instance. - * Multiple `IFirewallComponent.php` instances can be configured for different - parts or paths in your Webapp. - For example, a ***stateful*** instance that uses the - HTTP session to store user authentication tokens could be used by pages for - a portal GUI because this would prevent the need to repeatedly re-authenticate the user across - different pages. - Conversely, within the same webapp, a ***stateless*** FW component could be used to protect REST - endpoints where creation of the HTTP session would be unnecessary overhead - because credentials could be provided in every request (e.g. via x509 or BASIC). +the required `IFirewallComponent.php` instance. + * Multiple `IFirewallComponent.php` instances can be configured for different + parts or paths in your Webapp. + For example, a ***stateful*** instance that uses the + HTTP session to store user authentication tokens could be used by pages for + a portal GUI because this would prevent the need to repeatedly re-authenticate the user across + different pages. + Conversely, within the same webapp, a ***stateless*** FW component could be used to protect REST + endpoints where creation of the HTTP session would be unnecessary overhead + because credentials could be provided in every request (e.g. via X.509 or BASIC). * Client code invokes `$myfirewallComponent->getAuthentication();` on the FW component to get an `IAutenticationToken` instance. This starts the automatic **Token Resolution Process** : - 1. An attempt is made to fetch a previously created token from HTTP session and return the token if available. - A token may not exist for the current request because: + 1. An attempt is made to fetch a previously created token from HTTP session and return the token if available. + A token may not exist for the current request because: - * this is the initial request and a token has not been created yet, - * the FW component configuration is stateless and prevents session-creation and/or, + * this is the initial request and a token has not been created yet, + * the FW component configuration is stateless and prevents session-creation and/or, * the token is `stateless` which prevents it from being stored in session. - 2. If a token is not available, then the configured **pre-authenticating** + 2. If a token is not available, then the configured **pre-authenticating** tokens are iterated in order in an attempt to automatically create a token: - * The first successfully created and authenticated pre-auth token is returned. + * The first successfully created and authenticated pre-auth token is returned. 3. If a pre-authenticating token could not be be created, `null` is returned. - 4. If `null` is returned, client code can optionally choose to manually create an authentication token. - The token must then be manually authenticated using the `$myfirewallComponent->authenticate($aToken)` method. - * For example, a `UsernamePasswordAuthenticationToken.php` requires credentials - are manually input from the user, usually via a form POST. In this example, - the un/pw token is not a pre-authenticating token as it can't be - automatically created/resolved (the credentials are not + 4. If `null` is returned, client code can optionally choose to manually create an authentication token. + The token must then be manually authenticated using the `$myfirewallComponent->authenticate($aToken)` method. + * For example, a `UsernamePasswordAuthenticationToken.php` requires credentials + are manually input from the user, usually via a form POST. In this example, + the un/pw token is not a pre-authenticating token as it can't be + automatically created/resolved (the credentials are not provided in each/every request unlike client certificates or http basic). -Core Interfaces and (Implementations) +Core Interfaces and (Implementations) ===================================== - -IAuthentication.php + +IAuthentication.php ------------------- -(`X509AuthenticationToken.php`, `UsernamePasswordAuthenticationToken.php`, `SimpleSamlPhpAuthToken.php`) +(`X509AuthenticationToken.php`, `UsernamePasswordAuthenticationToken.php`, `SimpleSamlPhpAuthToken.php`) * Authentication tokens support different authentication mechanisms, see individual -tokens for details on their configuration. -* A token is created and used to authenticate the current user/request (or not). -* Pre-authenticating Tokens (e.g. X09AuthenticationToken and SimpleSamlPhpAuthToken) +tokens for details on their configuration. +* A token is created and used to authenticate the current user/request (or not). +* Pre-authenticating Tokens (e.g. X09AuthenticationToken and SimpleSamlPhpAuthToken) are created and authenticated automatically and then returned to client code by an IFirewallComponent. -* Tokens that are not pre-authenticating (e.g. UsernamePasswordAuthenticationToken) -need to be created manually in client code and then passed to an IFirwallComponent -for subsequent authentication. +* Tokens that are not pre-authenticating (e.g. UsernamePasswordAuthenticationToken) +need to be created manually in client code and then passed to an IFirwallComponent +for subsequent authentication. * Tokens are used by client code and by the framework. FirewallComponentManager.php ---------------------------- -Used by client code - Singleton class to get the list of configured +Used by client code - Singleton class to get the list of configured IFirewallComponent instances for use within client code. IFirewallComponent.php ---------------------- -(`FirewallComponent.php`) +(`FirewallComponent.php`) -Used by client code - Defines a top-level class intended for use by client code to authenticate -HTTP requests by invoking the **Token Resolution Process**. This component -can also be used manually from client code to authenticate/change the currently -authenticated principal. Instances can be fetched using the FirewallComponentManager. +Used by client code - Defines a top-level class intended for use by client code to authenticate +HTTP requests by invoking the **Token Resolution Process**. This component +can also be used manually from client code to authenticate/change the currently +authenticated principal. Instances can be fetched using the FirewallComponentManager. IConfigFirewallComponent.php ------------------------------------ (`MyConfig1.php`) -Framework object - Class used to configure an individual IFirewallComponent. -You will have to modify this file (or another implementation) for your authentication -requirements. +Framework object - Class used to configure an individual IFirewallComponent. +You will have to modify this file (or another implementation) for your authentication +requirements. ISecurityContext.php -------------------------- (`MySecurityContext.php`) -Framework object - Get or set an IAuthentication token for current thread of execution. -Depending on the configuration, the token may be retrieved/stored in HTTP session +Framework object - Get or set an IAuthentication token for current thread of execution. +Depending on the configuration, the token may be retrieved/stored in HTTP session which is necessary to prevent re-authentication across multiple page requests (e.g. to prevent re-entering a un/pw for each page). - -Calling `SecurityContext::getAuthentication()` invokes the automatic **Token Resolution Process** + +Calling `SecurityContext::getAuthentication()` invokes the automatic **Token Resolution Process** -IAuthenticationManager.php +IAuthenticationManager.php -------------------------- (`MyAuthenticationManager.php`) -Framework object - Provides a single 'authenticate($anIAuthToken)' method for authenticating a -given token. The manager will iterate all the configured IAuthenticationProviderS -in an attempt to authenticate the given token. A token is returned on the first successful authentication. +Framework object - Provides a single 'authenticate($anIAuthToken)' method for authenticating a +given token. The manager will iterate all the configured IAuthenticationProviderS +in an attempt to authenticate the given token. A token is returned on the first successful authentication. -IAuthenticationProvider.php +IAuthenticationProvider.php --------------------------- (`GOCDBAuthProvider.php`, `SampleAuthProvider.php`) Framework object - Used to authenticate IAuthentication tokens. A single provider can authenticate -different types of token as indicated by its `supports($token)` method. -SampleAuthProvider.php is a demo sample and should NOT be used in production. +different types of token as indicated by its `supports($token)` method. +SampleAuthProvider.php is a demo sample and should NOT be used in production. -IUserDetails.php +IUserDetails.php ---------------- -(`GOCDBUserDetails.php`) +(`GOCDBUserDetails.php`) -Framework object - Stores information about a user and is a member variable of an IAuthentication object. -This allows non-security related user information such as email addresses, -telephone numbers etc to be stored in a convenient location inside the token. This object -also encapsulates the user's granted authorities (i.e. roles). +Framework object - Stores information about a user and is a member variable of an IAuthentication object. +This allows non-security related user information such as email addresses, +telephone numbers etc to be stored in a convenient location inside the token. This object +also encapsulates the user's granted authorities (i.e. roles). -IUserDetailsService.php +IUserDetailsService.php ----------------------- (`GOCDBUserDetailsService.php`) Framework object - Abstracts the local credential store (typically a DB) for loading user-specific data. -The interface defines a public method `loadUserByUsername($aUsernameString)` +The interface defines a public method `loadUserByUsername($aUsernameString)` which simplifies support for new data-access strategies. -Typical Usage +Typical Usage ============= -The GocDB code calls the authentication framework code from a single file: +The GocDB code calls the authentication framework code from a single file: `htdocs/web_portal/components/Get_User_Principle.php` (see this file for details). - -Sample usage is: + +Sample usage is: ```php getFirewallArray(); + $firewallArray = $fwMan->getFirewallArray(); // select which IFirewallComponent you need (by array key) $firewall = $firewallArray['fwC1']; - // invoke 'automatic' token resolution process to authenticate user + // invoke 'automatic' token resolution process to authenticate user $auth = $firewall->getAuthentication(); if ($auth == null) { - // A token could not be automatically resolved for the current request, + // A token could not be automatically resolved for the current request, // you could therefore manually create a token e.g. get a un/pw - // from the user and attempt authentication using a different token: + // from the user and attempt authentication using a different token: // try { // $unPwToken = new org\gocdb\security\authentication\ // UsernamePasswordAuthenticationToken("test", "test"); // $auth = $fwComponents['fwC1']->authenticate($unPwToken); // return $auth->getPrinciple() // } catch(org\gocdb\security\authentication\AuthenticationException $ex){ } - - return null; - } - // $auth->$auth->getAuthorities(); // roles - // $auth->getDetails(); // custom user details object - return $auth->getPrinciple(); // string that uniquely identifies user + + return null; + } + // $auth->$auth->getAuthorities(); // roles + // $auth->getDetails(); // custom user details object + return $auth->getPrinciple(); // string that uniquely identifies user } ``` - -An explicit authentication and logout (i.e. removal of the security context) -can be achieved using the following: + +An explicit authentication and logout (i.e. removal of the security context) +can be achieved using the following: ```php - // get required IFirewallComponent instance as shown above - $firewall->authenticate($authToken); // to authenticate - // or + // get required IFirewallComponent instance as shown above + $firewall->authenticate($authToken); // to authenticate + // or $firewall->authenticate(null); // to logout/remove token ``` How do I support a new authentication mechanism? ================================================ -* Edit an existing token class or provide a new `IAuthentication.php` implementation for your chosen auth-mechanism +* Edit an existing token class or provide a new `IAuthentication.php` implementation for your chosen auth-mechanism * This object MUST implement IAuthentication. * Implementations go in the `AuthTokens` dir. -* Edit `GOCDBAuthProvider.php` or provide a new `IAuthenticationProvider.php` implementation to authenticate your +* Edit `GOCDBAuthProvider.php` or provide a new `IAuthenticationProvider.php` implementation to authenticate your IAuthentication object. - * Usually authentication is done by comparing the IUserDetails object that is returned + * Usually authentication is done by comparing the IUserDetails object that is returned from your IUserDetailsService. - * Implementations go in the `AuthProviders` dir. + * Implementations go in the `AuthProviders` dir. * Optional: Edit `GOCDBUserDetailsService.php` or provide a new `IUserDetailsService.php` implementation to load user-specific data -from your local credential repository and return your IUserDetails object. - * Implementations should go in `UserDetailsServices` dir. +from your local credential repository and return your IUserDetails object. + * Implementations should go in `UserDetailsServices` dir. -* Optional: Edit `GOCDBUserDetails.php` or provide a new `IUserDetails.php` implementation to store your user-specific data. - * Implementations go in `UserDetails` dir. - * Note: Take care to correctly fulfil the contract of the public API, in particular, - you must ensure the non-null contracts as detailed for each method are correctly enforced! +* Optional: Edit `GOCDBUserDetails.php` or provide a new `IUserDetails.php` implementation to store your user-specific data. + * Implementations go in `UserDetails` dir. + * Note: Take care to correctly fulfil the contract of the public API, in particular, + you must ensure the non-null contracts as detailed for each method are correctly enforced! -* Edit `MyConfig1.php` or define your own `IConfigFirewallComponent.php` to configure your setup +* Edit `MyConfig1.php` or define your own `IConfigFirewallComponent.php` to configure your setup -* Modify `FirewallComponentManager.php` to build/return the required IFirewallComponent - instances to client code. +* Modify `FirewallComponentManager.php` to build/return the required IFirewallComponent + instances to client code. * Use the sample code shown in the Typical Usage section to resolve/create/authenticate a token. @@ -245,6 +245,6 @@ TODO Use XML/YAML files to configure IConfigFirewallComponent and FirewallComponentManager rather than manually creating these instances for your configuration. -Create a top-level 'IFirewall.php' class that would use 'intercept-URL' pattern matching -to return the correct IFirewallComponent (as an alternative to 'manually' +Create a top-level 'IFirewall.php' class that would use 'intercept-URL' pattern matching +to return the correct IFirewallComponent (as an alternative to 'manually' requesting the required IFirewallComponent via the FirewallComponentManager). diff --git a/lib/Authentication/UserDetailsServices/GOCDBUserDetailsService.php b/lib/Authentication/UserDetailsServices/GOCDBUserDetailsService.php index 06ab5df47..06bd79560 100644 --- a/lib/Authentication/UserDetailsServices/GOCDBUserDetailsService.php +++ b/lib/Authentication/UserDetailsServices/GOCDBUserDetailsService.php @@ -17,7 +17,7 @@ class GOCDBUserDetailsService implements IUserDetailsService { /** * Locates the user based on the given username string. * The username string must uniquely identify the user (its format can differ - * depending on the authentication mechanism e.g. could be a DN string for x509). + * depending on the authentication mechanism e.g. could be a DN string for X.509). * * @param string $username the user string identifying the user whose data is required. * @return \IUserDetails implementation (never null) diff --git a/lib/Doctrine/entities/APIAuthentication.php b/lib/Doctrine/entities/APIAuthentication.php index 548ac15bf..e4288f67c 100644 --- a/lib/Doctrine/entities/APIAuthentication.php +++ b/lib/Doctrine/entities/APIAuthentication.php @@ -16,7 +16,7 @@ * The APIAuthenticationEntity defines a credential that can be used to makce * changes throught he API for a specific {@see Site}. Each site can have * 0-many APIAuthentication entities associated with it. Each entity has an ID, - * type, identifier (e.g. DN for x509) and parent site. + * type, identifier (e.g. DN for X.509) and parent site. * * @author George Ryall (github.com/GRyall) * @@ -36,12 +36,12 @@ class APIAuthentication protected $parentSite = null; /** - * Defines the type of the authentication entity (e.g 'x509'). + * Defines the type of the authentication entity (e.g 'X.509'). * @Column(type="string", nullable=false) */ protected $type = null; /** - * The unique identifier for the authentication (e.g. DN for x509) + * The unique identifier for the authentication (e.g. DN for X.509) * @Column(type="string", nullable=false) */ protected $identifier = null; diff --git a/lib/Doctrine/entities/Service.php b/lib/Doctrine/entities/Service.php index 7e7219d42..4981296bb 100644 --- a/lib/Doctrine/entities/Service.php +++ b/lib/Doctrine/entities/Service.php @@ -197,7 +197,7 @@ public function getMonitored() { } /** - * Defines the DN of the services x509 certificate. + * Defines the DN of the services X.509 certificate. * @return string or null */ public function getDn() { diff --git a/lib/Doctrine/entities/User.php b/lib/Doctrine/entities/User.php index d26749367..92f6ba3a0 100644 --- a/lib/Doctrine/entities/User.php +++ b/lib/Doctrine/entities/User.php @@ -164,7 +164,7 @@ public function getWorkingHoursEnd() { } /** - * Get the user's unique ID string, typically an x509 DN string. + * Get the user's unique ID string, typically an X.509 DN string. * This should return null once the user has user identifiers. * @return string */ @@ -281,7 +281,7 @@ public function setWorkingHoursEnd($workingHoursEnd) { } /** - * Set the user's unique ID string, typically an x509 DN string. + * Set the user's unique ID string, typically an X.509 DN string. * This should only be used to set the value to null * when user identifiers are first added to an old user. * @param string $certificateDn diff --git a/lib/Gocdb_Services/APIAuthenticationService.php b/lib/Gocdb_Services/APIAuthenticationService.php index 8b939a04a..17a5b119c 100644 --- a/lib/Gocdb_Services/APIAuthenticationService.php +++ b/lib/Gocdb_Services/APIAuthenticationService.php @@ -37,7 +37,7 @@ function __construct() { * Returns the APIAuthentication entity associated with the given identifier. * * @param string $ident Identifier (e.g. X.509 DN as string) - * @param string $type Identifyer type (e.g. "X509") + * @param string $type Identifyer type (e.g. "X.509") * @return \APIAuthentication APIAuthentication associated with this identifier */ public function getAPIAuthentication($ident, $type) { @@ -253,10 +253,10 @@ private function validate($data, $identifier, $type) { throw new \Exception($error); } } - //If the entity is of type X509, do a more thorough check than the validate service (as we know the type) + //If the entity is of type X.509, do a more thorough check than the validate service (as we know the type) //Note that we are allowing ':' as they can appear in robot DN's - if ($type == 'X509' && !preg_match("/^(\/[A-Za-z]+=[a-zA-Z0-9\/\-\_\s\.,'@:\/]+)*$/", $identifier)) { - throw new \Exception("Invalid x509 DN"); + if ($type == 'X.509' && !preg_match("/^(\/[A-Za-z]+=[a-zA-Z0-9\/\-\_\s\.,'@:\/]+)*$/", $identifier)) { + throw new \Exception("Invalid X.509 DN"); } //If the entity is of type OIDC subject, do a more thorough check again diff --git a/lib/Gocdb_Services/User.php b/lib/Gocdb_Services/User.php index 9905501c4..f724aa992 100644 --- a/lib/Gocdb_Services/User.php +++ b/lib/Gocdb_Services/User.php @@ -573,6 +573,8 @@ public function getAuthTypes($reducedRealms=true) { if (strpos($authTokenName, 'Shib') !== false) { $authTypes = array_merge($authTypes, $shibRealms); } + // This checks AuthToken class names, so 'X509' (not 'X.509' is + // needed here). if (strpos($authTokenName, 'X509') !== false) { $authTypes = array_merge($authTypes, $x509Realms); } diff --git a/tests/unit/lib/Gocdb_Services/APIAuthenticationServiceTest.php b/tests/unit/lib/Gocdb_Services/APIAuthenticationServiceTest.php index 213d5ed81..6c49862f1 100644 --- a/tests/unit/lib/Gocdb_Services/APIAuthenticationServiceTest.php +++ b/tests/unit/lib/Gocdb_Services/APIAuthenticationServiceTest.php @@ -169,7 +169,7 @@ public function testGetAPIAuthentication() ); $ident = '/CN=A Dummy Subject'; - $type = 'X509'; + $type = 'X.509'; // Start with no APIAuthentication entities to be found $this->assertNull( $authEntServ->getAPIAuthentication($ident, $type), diff --git a/tests/unit/lib/Gocdb_Services/RoleServiceTest2.php b/tests/unit/lib/Gocdb_Services/RoleServiceTest2.php index 54f82694a..d75100f57 100644 --- a/tests/unit/lib/Gocdb_Services/RoleServiceTest2.php +++ b/tests/unit/lib/Gocdb_Services/RoleServiceTest2.php @@ -204,12 +204,13 @@ private function addAPIAuthEntity() $this->user, array( "IDENTIFIER" => $this->user->getUserIdentifiers()[0]->getKeyValue(), - "TYPE" => "X509", + "TYPE" => "X.509", "ALLOW_WRITE" => false ) ); return; } + /** * Tests begin here */ diff --git a/tests/unit/lib/Gocdb_Services/SiteServiceTest.php b/tests/unit/lib/Gocdb_Services/SiteServiceTest.php index 60a5744dc..85bf39ed5 100644 --- a/tests/unit/lib/Gocdb_Services/SiteServiceTest.php +++ b/tests/unit/lib/Gocdb_Services/SiteServiceTest.php @@ -212,7 +212,7 @@ public function testAddAPIAuthentication() $site, $user, array('IDENTIFIER' => '/CN=A Dummy Subject' , - 'TYPE' => 'X509', + 'TYPE' => 'X.509', 'ALLOW_WRITE' => false) ); diff --git a/tests/unit/lib/Gocdb_Services/UserServiceTest.php b/tests/unit/lib/Gocdb_Services/UserServiceTest.php index d74ddc654..f97bddfcc 100644 --- a/tests/unit/lib/Gocdb_Services/UserServiceTest.php +++ b/tests/unit/lib/Gocdb_Services/UserServiceTest.php @@ -208,7 +208,7 @@ public function testAddAPIAuthentication() $authEnt = new \APIAuthentication(); $authEnt->setIdentifier($userIdentifier['VALUE']); - $authEnt->setType("X509"); + $authEnt->setType("X.509"); $user = $userService->getUserByPrinciple($userIdentifier['VALUE']); diff --git a/tests/writeAPI/abstractClass.php b/tests/writeAPI/abstractClass.php index 650175bcc..93a66480f 100644 --- a/tests/writeAPI/abstractClass.php +++ b/tests/writeAPI/abstractClass.php @@ -179,7 +179,7 @@ protected function wellFormattedWriteAPICall($method, $requestContents, $authIde $urlString .= '/' . $entKey; } - return $this->arbitaryValuesWriteAPICall($method, $urlString, $requestContents, 'X509', $authIdent); + return $this->arbitaryValuesWriteAPICall($method, $urlString, $requestContents, 'X.509', $authIdent); } /** @@ -234,7 +234,7 @@ protected function createSampleSite($append = "") #We need a credential that can access the writeAPI associated with the sites $authEnt = new \APIAuthentication(); $authEnt->setIdentifier($this->validAuthIdent); - $authEnt->setType('X509'); + $authEnt->setType('X.509'); $site->addAPIAuthenticationEntitiesDoJoin($authEnt); #And then we get Doctrine to update the DB diff --git a/todo.md b/todo.md index 87ffb1e26..eb01c233d 100644 --- a/todo.md +++ b/todo.md @@ -62,23 +62,6 @@ ## Maybe Todo * Add LoA attribute to AuthToken details -* Support account linking where a user would need to authenticate multiple times using the different - AAI supported methods in order to link those identities to a single (possibly existing) account: - * Update DB schema so that a user account has one-to-many identities rather than a single ID - * Record additional information about which login-route/security-realm is associated with each ID - * Modify the authentication lib so that the authentication-context can handle -a collection of AuthTokens rather than a single AuthToken during the same HTTP session - * Enable linking a new/unregistered ID to an existing account: On registering, -provide an option to allow the new ID to be associated with an existing account -rather than creating a new/separate account. - * Link two existing accounts together: Provide interface to allow joining/merging -two existing accounts (will need to merge existing roles, remove duplicate roles etc) - * To perform either of these account linking scenarios, user will be required to -authenticate for all the authentication-mechanisms during the same HTTP session -(e.g. authenticate with x509, then re-authenticate via IdP). Only after successfully -authenticating with the multiple login mechanisms, should they be able to link those accounts together. - * Or use Unity / Perun to do the account linking for us? - * Add filtering of resources by 'project' ? * Add 'project' URL param to PI get_project, get_site, get_service, get_downtime ? * Introduce READ action for roles? - currently, once a user is authenticated, all info can