Commit 614b01c2 authored by Arnaud Pauget's avatar Arnaud Pauget
Browse files

Merge branch 'feat/14896_SSO_Kerberos' into 'develop'

Feat/14896 sso kerberos

See merge request !689
parents 15cde1c8 66b873e5
Pipeline #14026 failed with stages
in 48 seconds
......@@ -142,22 +142,43 @@ abstract class AbstractRequest
*/
protected function getAuthentication()
{
if (isset($_SERVER['PHP_AUTH_USER'])) {
$this->authentication = new basicAuthentication($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
} elseif (isset($_SERVER['PHP_AUTH_DIGEST'])) {
$neededParts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1);
$data = array();
$keys = implode('|', array_keys($neededParts));
preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@', $_SERVER['PHP_AUTH_DIGEST'], $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$data[$match[1]] = $match[3] ? $match[3] : $match[4];
unset($neededParts[$match[1]]);
}
$this->authentication = $this->selectAuthentication();
}
$this->authentication = new digestAuthentication($data['username'], $data['nonce'], $data['uri'], $data['response'], $data['qop'], $data['nc'], $data['cnonce']);
}
protected function selectAuthentication()
{
$authModes = \laabs::getAuthModes();
foreach ($authModes as $authMode) {
switch ($authMode) {
case LAABS_BASIC_AUTH:
if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
return new basicAuthentication($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
}
break;
case LAABS_DIGEST_AUTH:
if (isset($_SERVER['PHP_AUTH_DIGEST'])) {
$neededParts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1);
$data = array();
$keys = implode('|', array_keys($neededParts));
preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@', $_SERVER['PHP_AUTH_DIGEST'], $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$data[$match[1]] = $match[3] ? $match[3] : $match[4];
unset($neededParts[$match[1]]);
}
return new digestAuthentication($data['username'], $data['nonce'], $data['uri'], $data['response'], $data['qop'], $data['nc'], $data['cnonce']);
}
break;
case LAABS_REMOTE_AUTH:
if (isset($_SERVER['REMOTE_USER']) && isset($_SERVER['AUTH_TYPE'])) {
return new remoteAuthentication($_SERVER['REMOTE_USER'], $_SERVER['AUTH_TYPE']);
}
break;
}
}
}
}
\ No newline at end of file
<?php
namespace core\Request;
/**
* Class to represent app authentication
*/
class remoteAuthentication
extends abstractAuthentication
{
public static $mode = LAABS_REMOTE_AUTH;
public $remoteUser;
public $authType;
public function __construct($remoteUser, $authType)
{
$this->remoteUser = $remoteUser;
$this->authType = $authType;
}
}
\ No newline at end of file
......@@ -137,6 +137,7 @@ const LAABS_BATCH_STATUS_COMPLETED = "Completed";
const LAABS_BASIC_AUTH = "basic";
const LAABS_DIGEST_AUTH = "digest";
const LAABS_APP_AUTH = "app";
const LAABS_REMOTE_AUTH = "remote";
// TOKENS
// Operations
......
......@@ -1392,4 +1392,14 @@ trait laabsAppTrait
}
/**
* Get the auth methods
*
* @return array
*/
public static function getAuthModes()
{
return self::getList('LAABS_AUTH_MODES');
}
}
......@@ -52,4 +52,21 @@
SetEnv LAABS_ERROR_URI recordsManagement/welcome/error
SetEnv LAABS_CRYPT_KEY mySecretKey
### AUTHENTICATION WITH KERBEROS ###
# SetEnv LAABS_AUTH_MODES remote;basic;digest
# <Directory "/var/www/laabs/web">
# <If "'%{HTTP:User-Agent}' !~ m#service(.*)$#">
# AuthType Kerberos
# AuthName "KERBEROS AUTHENTICATION"
# KrbAuthRealms DOMAIN.COM
# KrbServiceName HTTP
# Krb5Keytab /etc/apache2/kerb.keytab
# KrbMethodNegotiate On
# KrbMethodK5Passwd Off
# Require valid-user
# </If>
# </Directory>
</VirtualHost>
......@@ -65,34 +65,102 @@ class userAuthentication
*/
public function login($userName, $password)
{
// Check userAccount exists
$currentDate = \laabs::newTimestamp();
// Check userAccount exists and get it
$userAccount = $this->getUserByName($userName);
$this->checkEnabled($userAccount);
// Check password ans status
$userLogin = $this->checkCredentials($userAccount, $password);
if (isset($this->securityPolicy['sessionTimeout'])) {
$tokenDuration = $this->securityPolicy['sessionTimeout'];
} else {
$tokenDuration = 86400;
}
// Set token
$this->setToken($userLogin, $tokenDuration);
// Require password change
if ($this->securityPolicy['passwordValidity'] && $this->securityPolicy["passwordValidity"] != 0) {
$diff = ($userLogin->lastLogin->getTimestamp() - $userAccount->passwordLastChange->getTimestamp()) / $tokenDuration;
if ($diff > $this->securityPolicy['passwordValidity']) {
throw \laabs::newException('auth/userPasswordChangeRequestException');
}
}
if ($userAccount->passwordChangeRequired == true) {
\laabs::setToken('TEMP-AUTH', $accountToken, $tokenDuration);
\laabs::unsetToken('AUTH');
throw \laabs::newException('auth/userPasswordChangeRequestException');
}
return $userAccount;
}
/**
* Log a remote user
* @param string $userName
*
* @return auth/userAccount
*/
public function logRemoteUser($userName)
{
// Check userAccount exists and get it
$userAccount = $this->getUserByName($userName);
$this->checkEnabled($userAccount);
$userLogin = \laabs::newInstance('auth/userLogin');
$userLogin->accountId = $userAccount->accountId;
$userLogin->lastIp = $_SERVER["REMOTE_ADDR"];
if (isset($this->securityPolicy['sessionTimeout'])) {
$tokenDuration = $this->securityPolicy['sessionTimeout'];
} else {
$tokenDuration = 86400;
}
// Set token
$this->setToken($userLogin, $tokenDuration);
return $userAccount;
}
/**
* Get user from userName
* @param string $userName
*
* @return auth/account
* @throws auth/authenticationException when username not found
*/
public function getUserByName(string $userName)
{
$exists = $this->sdoFactory->exists('auth/account', array('accountName' => $userName));
if (!$exists) {
throw \laabs::newException('auth/authenticationException', 'Username and / or password invalid', 401);
}
$userAccount = $this->sdoFactory->read('auth/account', array('accountName' => $userName));
return $this->sdoFactory->read('auth/account', array('accountName' => $userName));
}
/**
* Check user password and hability to login
* @param object $userAccount
*
* @return object
*/
protected function checkCredentials($userAccount, $password)
{
$currentDate = \laabs::newTimestamp();
// Create user login object
$userLogin = \laabs::newInstance('auth/userLogin');
$userLogin->accountId = $userAccount->accountId;
$userLogin->lastIp = $_SERVER["REMOTE_ADDR"];
// Check enabled
if ($userAccount->enabled != true) {
$e = \laabs::newException(
'auth/authenticationException',
'User %1$s is disabled',
403,
null,
array($userName)
);
throw $e;
}
// Check password
if (!password_verify($password, $userAccount->password) && hash($this->passwordEncryption, $password) != $userAccount->password) {
// Update bad password count
......@@ -119,6 +187,10 @@ class userAuthentication
throw \laabs::newException('auth/authenticationException', 'Username and / or password invalid', 401);
}
if (password_needs_rehash($userAccount->password, PASSWORD_DEFAULT)) {
$userLogin->password = password_hash($password, PASSWORD_DEFAULT);
}
// Check locked
if ($userAccount->locked == true) {
if (!isset($this->securityPolicy['lockDelay']) // No delay while locked
......@@ -137,36 +209,21 @@ class userAuthentication
$userLogin->tokenDate = null;
$userLogin->lastLogin = $currentDate;
if (password_needs_rehash($userAccount->password, PASSWORD_DEFAULT)) {
$userLogin->password = password_hash($password, PASSWORD_DEFAULT);
}
$this->sdoFactory->update($userLogin, 'auth/account');
if (isset($this->securityPolicy['sessionTimeout'])) {
$tokenDuration = $this->securityPolicy['sessionTimeout'];
} else {
$tokenDuration = 86400;
}
return $userLogin;
}
/**
* Sets the auth token
* @param object $userLogin
* @param int $tokenDuration
*/
public function setToken($userLogin, $tokenDuration)
{
$accountToken = new \StdClass();
$accountToken->accountId = $userAccount->accountId;
$accountToken->accountId = $userLogin->accountId;
$userToken = \laabs::setToken('AUTH', $accountToken, $tokenDuration);
if ($this->securityPolicy['passwordValidity'] && $this->securityPolicy["passwordValidity"] != 0) {
$diff = ($currentDate->getTimestamp() - $userAccount->passwordLastChange->getTimestamp()) / $tokenDuration;
if ($diff > $this->securityPolicy['passwordValidity']) {
throw \laabs::newException('auth/userPasswordChangeRequestException');
}
}
if ($userAccount->passwordChangeRequired == true) {
\laabs::setToken('TEMP-AUTH', $accountToken, $tokenDuration);
\laabs::unsetToken('AUTH');
throw \laabs::newException('auth/userPasswordChangeRequestException');
}
return $userAccount;
}
/**
......@@ -230,6 +287,26 @@ class userAuthentication
}
}
/**
* Check if user is enabled
* @param object $userAccount
*
* @return object
*/
protected function checkEnabled($userAccount)
{
if ($userAccount->enabled != true) {
$e = \laabs::newException(
'auth/authenticationException',
'User %1$s is disabled',
403,
null,
array($userName)
);
throw $e;
}
}
/**
* Log out a user
*/
......
......@@ -106,6 +106,21 @@ class authentication
}
break;
case LAABS_REMOTE_AUTH:
try {
$userAuthenticationController = \laabs::newController('auth/userAuthentication');
$this->requestToken = $this->account = $userAuthenticationController->logRemoteUser($requestAuth->remoteUser);
$this->accountId = $this->account->accountId;
\laabs::kernel()->response->code = 307;
\laabs::kernel()->response->setHeader('Location', '/');
\laabs::kernel()->sendResponse();
\laabs::kernel()->end();
} catch (\Exception $e) {
throw $e;
}
break;
/*case LAABS_DIGEST_AUTH:
if ($this->authenticationService->logIn($requestAuth->username, $requestAuth->nonce, $requestAuth->uri, $requestAuth->response, $requestAuth->qop, $requestAuth->nc, $requestAuth->cnonce)) {
$token = $this->encrypt($_SESSION['dependency']['authentication']['credential']);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment