Skip to content
This repository has been archived by the owner on Nov 25, 2020. It is now read-only.

Commit

Permalink
Reorganize MemorySafe. Add a context identifier to handle multiple cr…
Browse files Browse the repository at this point in the history
…edential sources. For storing when passed via ENV CLi.
  • Loading branch information
cdujeu committed Nov 8, 2016
1 parent 8ce3909 commit 1f90363
Show file tree
Hide file tree
Showing 16 changed files with 264 additions and 214 deletions.
6 changes: 1 addition & 5 deletions core/src/core/src/pydio/Core/Controller/CliRunner.php
Expand Up @@ -105,11 +105,7 @@ public static function applyActionInBackground(ContextInterface $ctx, $actionNam
$cmd .= " --$key=" . escapeshellarg($value);
}
}
$envSet = false;
if ($ctx->getRepository()->getContextOption($ctx, "USE_SESSION_CREDENTIALS")) {
$envSet = MemorySafe::setEnv();
}

$envSet = MemorySafe::setEnvForContext($ctx);
// NOW RUN COMMAND
$res = self::runCommandInBackground($cmd, $logFile);

Expand Down
27 changes: 15 additions & 12 deletions core/src/core/src/pydio/Core/Exception/PydioPromptException.php
Expand Up @@ -20,6 +20,7 @@
*/
namespace Pydio\Core\Exception;

use Pydio\Core\Http\Middleware\WorkspaceAuthMiddleware;
use Pydio\Core\Http\Response\JSONSerializableResponseChunk;
use Pydio\Core\Http\Response\XMLSerializableResponseChunk;

Expand Down Expand Up @@ -78,31 +79,33 @@ public function __construct($promptType, $data, $messageString, $messageId = fal
/**
* Prompt user for credentials
* @param array $parameters
* @param string $passFieldName
* @param string $postSubmitCallback
* @throws PydioPromptException
* @return PydioPromptException
*/
public static function promptForWorkspaceCredentials($parameters, $passFieldName, $postSubmitCallback = ""){
$hiddens = [];
$getFields = [$passFieldName];
public static function promptForWorkspaceCredentials($parameters, $postSubmitCallback = ""){
$inputs = [];
foreach($parameters as $key => $value){
$hiddens[] = "<input type='hidden' name='$key' value='$value'>";
$getFields[] = $key;
if($key === WorkspaceAuthMiddleware::FORM_RESUBMIT_LOGIN) {
$inputs[] = "<input type='text' name='$key' value='$value' placeholder='Login'>";
}else if($key === WorkspaceAuthMiddleware::FORM_RESUBMIT_PASS){
$inputs[] = "<input type='password' name='$key' value='' placeholder='Password' autocomplete='off'>";
}else{
$inputs[] = "<input type='hidden' name='$key' value='$value'>";
}
}
throw new PydioPromptException(
return new PydioPromptException(
"confirm",
array(
"DIALOG" => "<div>
<h3>Credentials Required</h3>
<div class='dialogLegend'>Please provide a password to enter this workspace. You may have to manually redo the action you were currently trying to achieve.</div>
<div class='dialogLegend'>Please provide a password to enter this workspace.</div>
<form autocomplete='off'>
".implode("\n", $hiddens)."
<input style='width: 200px;' type='password' autocomplete='off' name='$passFieldName' value='' placeholder='Password'>
".implode("\n", $inputs)."
</form>
</div>
",
"OK" => array(
"GET_FIELDS" => $getFields,
"GET_FIELDS" => array_keys($parameters),
"EVAL" => $postSubmitCallback
),
"CANCEL" => array(
Expand Down
Expand Up @@ -36,16 +36,16 @@ class RepositoryLoadException extends PydioException
private $repository;
/**
* RepositoryLoadException constructor.
* @param RepositoryInterface|String $repository
* @param RepositoryInterface|String $workspace
* @param array $errors
*/
public function __construct($repository, $errors)
public function __construct($workspace, $errors)
{
if($repository instanceof RepositoryInterface){
$message = "Error while loading workspace ".$repository->getDisplay()." : ".implode("\n-", $errors);
$this->repository = $repository;
if($workspace instanceof RepositoryInterface){
$message = "Error while loading workspace ".$workspace->getDisplay()." : ".implode("\n-", $errors);
$this->repository = $workspace;
}else{
$message = "Error while loading workspace ".$repository." : ".implode("\n-", $errors);
$message = "Error while loading workspace ".$workspace." : ".implode("\n-", $errors);
}
parent::__construct($message, false, 5000);
}
Expand Down
35 changes: 28 additions & 7 deletions core/src/core/src/pydio/Core/Exception/WorkspaceAuthRequired.php
Expand Up @@ -34,16 +34,19 @@
*/
class WorkspaceAuthRequired extends PydioException {

private $repositoryId;
private $workspaceId;
private $requireLogin;

/**
* WorkspaceAuthRequired constructor.
* @param string $repositoryId
* @param string $workspaceId
* @param boolean $requireLogin
* @param string $message
*/
public function __construct($repositoryId, $message = "Authentication required for this workspace")
public function __construct($workspaceId, $requireLogin = false, $message = "Authentication required for this workspace")
{
$this->repositoryId = $repositoryId;
$this->workspaceId = $workspaceId;
$this->requireLogin = $requireLogin;
parent::__construct($message, false, null);
}

Expand All @@ -53,13 +56,31 @@ public function __construct($repositoryId, $message = "Authentication required f
* @throws WorkspaceAuthRequired
*/
public static function testWorkspace($workspaceObject, $userObject){
if($workspaceObject->getContextOption(Context::contextWithObjects($userObject, $workspaceObject), "USE_SESSION_CREDENTIALS") !== true){
$ctx = Context::contextWithObjects($userObject, $workspaceObject);
$instanceId = MemorySafe::contextUsesInstance($ctx);
if($instanceId === false){
return;
}
if(MemorySafe::loadCredentials() !== false){
if(MemorySafe::loadCredentials($instanceId) !== false){
return;
}
throw new WorkspaceAuthRequired($workspaceObject->getId());
$allowFreeLogin = ($workspaceObject->getContextOption($ctx, "SESSION_CREDENTIALS_FREE_LOGIN") === true);
throw new WorkspaceAuthRequired($workspaceObject->getId(), $allowFreeLogin);
}

/**
* @return string
*/
public function getWorkspaceId(){
return $this->workspaceId;
}

/**
* @return bool
*/
public function requiresLogin(){
return $this->requireLogin;
}


}
Expand Up @@ -76,6 +76,7 @@ protected static function authenticateFromCliParameters($options){
if($envPass !== false){
unset($optToken);
$optPass = $envPass;
MemorySafe::storeCredentials($optUser, $optPass);
}
}

Expand Down
Expand Up @@ -22,6 +22,7 @@

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Pydio\Access\Core\Model\AJXP_Node;
use Pydio\Auth\Core\MemorySafe;
use Pydio\Core\Exception\PydioException;

Expand All @@ -30,6 +31,7 @@
use Pydio\Core\Http\Server;
use Pydio\Core\Model\ContextInterface;
use Pydio\Core\Services\SessionService;
use Pydio\Core\Utils\Vars\InputFilter;
use Pydio\Core\Utils\Vars\StringHelper;

defined('AJXP_EXEC') or die('Access not allowed');
Expand All @@ -47,7 +49,9 @@ class WorkspaceAuthMiddleware
const RESUBMIT_AUTH_COUNT = "PYDIO_WORKSPACE_AUTH_RESUBMIT_COUNT";

const FORM_RESUBMIT_KEY = "workspace-auth-submission-id";
const FORM_RESUBMIT_LOGIN = "workspace-auth-login";
const FORM_RESUBMIT_PASS = "workspace-auth-password";
const FORM_SESSION_CREDS = "workspace-auth-test-session-credentials";

/**
* @param ServerRequestInterface $requestInterface
Expand All @@ -59,15 +63,33 @@ class WorkspaceAuthMiddleware
public static function handleRequest(ServerRequestInterface $requestInterface, ResponseInterface $responseInterface, callable $next = null){

$vars = $requestInterface->getParsedBody();
/** @var ContextInterface $ctx */
$ctx = $requestInterface->getAttribute("ctx");

if(isSet($vars[self::FORM_RESUBMIT_KEY]) && SessionService::has(self::RESUBMIT_AUTH_VARS."-".$vars[self::FORM_RESUBMIT_KEY]) && !empty($vars[self::FORM_RESUBMIT_PASS])){
$submittedId = $vars[self::FORM_RESUBMIT_KEY];
// Count a max number of submission?

/** @var ContextInterface $ctx */
$ctx = $requestInterface->getAttribute("ctx");
if($ctx->hasUser()){
$userId = $ctx->getUser()->getId();
}
if(isSet($vars[self::FORM_RESUBMIT_LOGIN]) && !empty($vars[self::FORM_RESUBMIT_LOGIN])){
$userId = InputFilter::sanitize($vars[self::FORM_RESUBMIT_LOGIN], InputFilter::SANITIZE_EMAILCHARS);
}

if(!empty($userId)){
$password = $vars[self::FORM_RESUBMIT_PASS];
MemorySafe::storeCredentials($ctx->getUser()->getId(), $password);
if(isSet($vars[self::FORM_SESSION_CREDS])){
$node = new AJXP_Node("pydio://".$userId."@".$vars[self::FORM_SESSION_CREDS]."/");
try{
MemorySafe::storeCredentials($userId, $password);
if(!is_writeable($node->getUrl())){
MemorySafe::clearCredentials();
}
}catch (\Exception $e){
MemorySafe::clearCredentials();
throw new PydioException($e->getMessage());
}
}
}

$newVars = SessionService::fetch(self::RESUBMIT_AUTH_VARS."-".$submittedId);
Expand All @@ -89,13 +111,21 @@ public static function handleRequest(ServerRequestInterface $requestInterface, R
// Generate a random ID.
$submissionId = StringHelper::generateRandomString(24);
SessionService::save(self::RESUBMIT_AUTH_VARS."-".$submissionId, $vars);
$parameters = [self::FORM_RESUBMIT_KEY => $submissionId];
$parameters = [];
if($ex->requiresLogin()){
$parameters[self::FORM_RESUBMIT_LOGIN] = $ctx->hasUser() ? $ctx->getUser()->getId() : "";
}
$parameters = array_merge($parameters, [
self::FORM_RESUBMIT_KEY => $submissionId,
self::FORM_RESUBMIT_PASS => "",
self::FORM_SESSION_CREDS => $ex->getWorkspaceId()
]);
$postSubmitCallback = "";
if($requestInterface->getAttribute("action") === "switch_repository"){
$postSubmitCallback = "ajaxplorer.loadXmlRegistry();";
}
// Will throw a prompt exception with all current values
return PydioPromptException::promptForWorkspaceCredentials($parameters, self::FORM_RESUBMIT_PASS, $postSubmitCallback);
throw PydioPromptException::promptForWorkspaceCredentials($parameters, $postSubmitCallback);

}

Expand Down
1 change: 0 additions & 1 deletion core/src/plugins/access.ajxp_conf/src/ConfAccessDriver.php
Expand Up @@ -309,7 +309,6 @@ public function editAction(ServerRequestInterface $requestInterface, ResponseInt
case "user_reorder_roles":
case "users_bulk_update_roles":
case "save_custom_user_params":
case "save_repository_user_params":
case "update_user_pwd":
$this->usersAction($requestInterface, $responseInterface);
break;
Expand Down
35 changes: 1 addition & 34 deletions core/src/plugins/access.ajxp_conf/src/UsersManager.php
Expand Up @@ -552,40 +552,7 @@ public function usersActions(ServerRequestInterface $requestInterface, ResponseI
$responseInterface = $responseInterface->withBody(new SerializableResponseStream(new UserMessage($mess["ajxp_conf.47"].$userId)));

break;

case "save_repository_user_params" :

$userId = InputFilter::sanitize($httpVars["user_id"], InputFilter::SANITIZE_EMAILCHARS);
$currentIsLogged = false;
if ($userId === $ctx->getUser()->getId()) {
$currentIsLogged = true;
$user = $ctx->getUser();
} else {
$user = $this->getUserIfAuthorized($ctx, $userId);
}

$wallet = $user->getPref("AJXP_WALLET");
if(!is_array($wallet)) $wallet = array();
$repoID = InputFilter::sanitize($httpVars["repository_id"], InputFilter::SANITIZE_ALPHANUM);
if (!array_key_exists($repoID, $wallet)) {
$wallet[$repoID] = array();
}
$options = $wallet[$repoID];
$existing = $options;
$newCtx = new Context($userId, $ctx->getRepositoryId());
$this->parseParameters($newCtx, $httpVars, $options, false, $existing);
$wallet[$repoID] = $options;
$user->setPref("AJXP_WALLET", $wallet);
$user->save();

if ($currentIsLogged) {
AuthService::updateSessionUser($user);
}

$responseInterface = $responseInterface->withBody(new SerializableResponseStream(new UserMessage($mess["ajxp_conf.47"].$userId)));

break;


case "update_user_pwd" :

$userId = isSet($httpVars["user_id"]) ? InputFilter::sanitize($httpVars["user_id"], InputFilter::SANITIZE_EMAILCHARS) : null;
Expand Down
7 changes: 4 additions & 3 deletions core/src/plugins/access.fs/FsAccessDriver.php
Expand Up @@ -2527,8 +2527,9 @@ public function makeSharedRepositoryOptions(ContextInterface $ctx, $httpVars)
"DEFAULT_RIGHTS" => "",
"DATA_TEMPLATE" => ""
];
if ($repository->getContextOption($ctx, "USE_SESSION_CREDENTIALS") === true) {
$newOptions["ENCODED_CREDENTIALS"] = MemorySafe::getEncodedCredentialString();
$sessionCredsInstance = MemorySafe::contextUsesInstance($ctx);
if($sessionCredsInstance !== false){
$newOptions["ENCODED_CREDENTIALS"] = MemorySafe::getInstance($sessionCredsInstance)->getEncodedCredentials();
}
$customData = [];
foreach ($httpVars as $key => $value) {
Expand All @@ -2543,7 +2544,7 @@ public function makeSharedRepositoryOptions(ContextInterface $ctx, $httpVars)
$newOptions["META_SOURCES"] = $repository->getContextOption($ctx, "META_SOURCES");
foreach ($newOptions["META_SOURCES"] as $index => &$data) {
if (isSet($data["USE_SESSION_CREDENTIALS"]) && $data["USE_SESSION_CREDENTIALS"] === true) {
$newOptions["META_SOURCES"][$index]["ENCODED_CREDENTIALS"] = MemorySafe::getEncodedCredentialString();
$newOptions["META_SOURCES"][$index]["ENCODED_CREDENTIALS"] = MemorySafe::getInstance()->getEncodedCredentials();
}
}
Controller::applyHook("workspace.share_metasources", [$ctx, &$newOptions["META_SOURCES"]]);
Expand Down
1 change: 1 addition & 0 deletions core/src/plugins/access.smb/manifest.xml
Expand Up @@ -10,6 +10,7 @@
<param name="PATH" type="string" label="CONF_MESSAGE[Uri]" description="CONF_MESSAGE[Path to the share and complementary URI if necessary]" mandatory="false"/>
<param name="DOMAIN" type="string" label="CONF_MESSAGE[Domain]" description="CONF_MESSAGE[Default domain to use with session credentials. The domain name ends with '/' or '\' depend on your system. Example: MyDomain\ or YourDomain/. Default is /]" mandatory="false"/>
<param name="CHMOD_VALUE" type="string" label="CONF_MESSAGE[File Creation Mask]" description="CONF_MESSAGE[Optionnaly apply a chmod operation. Value must be numeric, like 0777, 0644, etc.]" default="0666"/>
<param name="SESSION_CREDENTIALS_AUTHFRONT" type="string" label="CONF_MESSAGE[Session Credentials Authfront]" description="CONF_MESSAGE[Set this workspace to use only credentials from a specific authfront. Leave empty by default, can be useful to restrict credentials to e.g. CAS authfront (use authfront.cas value in that case).]" default=""/>
<global_param name="SMBCLIENT" type="string" label="CONF_MESSAGE[Smbclient]" description="CONF_MESSAGE[Path to smbclient executable, considered to be in the path by default.]" mandatory="true" default="smbclient"/>
<global_param name="SMB_PATH_TMP" type="string" label="CONF_MESSAGE[Path Tmp]" description="CONF_MESSAGE[OS Path Temporary if not the default one]" mandatory="true" default="/tmp"/>
<global_param name="SMB_ENABLE_ZIP" type="boolean" label="CONF_MESSAGE[Enable Zip]" description="CONF_MESSAGE[Enable zip creation for repositories using Samba access. Make sure that you are using a very fast network, otherwise it will be very long!]" mandatory="false" default="false"/>
Expand Down
2 changes: 1 addition & 1 deletion core/src/plugins/authfront.cas/CasAuthFrontend.php
Expand Up @@ -241,7 +241,7 @@ function tryToLogUser(ServerRequestInterface &$request, ResponseInterface &$resp
try {
$userObj = AuthService::logUser($cas_user, "", true);
AuthService::updateSessionUser($userObj);
MemorySafe::storeCredentials($cas_user, $_SESSION['PROXYTICKET']);
MemorySafe::storeCredentials($cas_user, $_SESSION['PROXYTICKET'], 'authfront.cas');
$_SESSION['LOGGED_IN_BY_CAS'] = true;

if (!empty($this->cas_additional_role)) {
Expand Down
3 changes: 2 additions & 1 deletion core/src/plugins/core.ajaxplorer/ajxp_mixins.xml
Expand Up @@ -5,7 +5,8 @@
<param group="MIXIN_MESSAGE[User Credentials]" name="USE_AUTH_STREAM" type="hidden" mandatory="true" default="true" />
<param group="MIXIN_MESSAGE[User Credentials]" name="USER" type="string" label="MIXIN_MESSAGE[User]" description="MIXIN_MESSAGE[User name - Can be overriden on a per-user basis (see users 'Personal Data' tab)]" mandatory="false"/>
<param group="MIXIN_MESSAGE[User Credentials]" name="PASS" type="password" label="MIXIN_MESSAGE[Password]" description="MIXIN_MESSAGE[User password - Can be overriden on a per-user basis.]" mandatory="false"/>
<param group="MIXIN_MESSAGE[User Credentials]" name="USE_SESSION_CREDENTIALS" type="boolean" label="MIXIN_MESSAGE[Session credentials]" description="MIXIN_MESSAGE[Try to use the current Pydio user credentials for connecting. Warning, the AJXP_SESSION_SET_CREDENTIALS config must be set to true!]" mandatory="false" default="false"/>
<param group="MIXIN_MESSAGE[User Credentials]" name="USE_SESSION_CREDENTIALS" type="boolean" label="MIXIN_MESSAGE[Session credentials]" description="MIXIN_MESSAGE[Use the current Pydio user credentials for connecting, or prompt the user. Warning, make sure to enable the 'Set Session Credentials' option in the main Authentication options.]" mandatory="false" default="false"/>
<param group="MIXIN_MESSAGE[User Credentials]" name="SESSION_CREDENTIALS_FREE_LOGIN" type="boolean" label="MIXIN_MESSAGE[Allow alternative login]" description="MIXIN_MESSAGE[If credentials are not set in the session, user is prompted to enter a password. Check this if the user can also enter an alternative login.]" mandatory="false" default="false"/>
<user_param name="USER" type="string" label="MIXIN_MESSAGE[User]" description="MIXIN_MESSAGE[User name]" mandatory="false"/>
<user_param name="PASS" type="password" label="MIXIN_MESSAGE[Password]" description="MIXIN_MESSAGE[User password]" mandatory="false"/>
</server_settings>
Expand Down

0 comments on commit 1f90363

Please sign in to comment.