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

Commit

Permalink
Adding OAuth Wrapper to the core access for Oauth2 authentification
Browse files Browse the repository at this point in the history
  • Loading branch information
ghecquet committed Mar 2, 2016
1 parent 935520a commit 5f1be52
Show file tree
Hide file tree
Showing 9 changed files with 281 additions and 22 deletions.
3 changes: 3 additions & 0 deletions core/src/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@
}
session_start();

if (isSet($_GET['code'])) {
$_SESSION['oauth_code'] = AJXP_Utils::sanitize($_GET['code'], AJXP_SANITIZE_ALPHANUM);
}
if (isSet($_GET["tmp_repository_id"]) || isSet($_POST["tmp_repository_id"])) {
try{
ConfService::switchRootDir(isset($_GET["tmp_repository_id"])?$_GET["tmp_repository_id"]:$_POST["tmp_repository_id"], true);
Expand Down
196 changes: 196 additions & 0 deletions core/src/plugins/core.access/src/Stream/OAuthWrapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
<?php
/*
* Copyright 2007-2016 Abstrium SAS <team (at) pyd.io>
* This file is part of the Pydio Enterprise Distribution.
* It is subject to the End User License Agreement that you should have
* received and accepted along with this distribution.
*/

namespace Pydio\Access\Core\Stream;

defined('AJXP_EXEC') or die('Access not allowed');

require_once(AJXP_BIN_FOLDER . '/guzzle/vendor/autoload.php');

use AJXP_SchemeTranslatorWrapper;
use AJXP_Safe;
use AJXP_Utils;
use AuthService;
use CacheService;
use CommerceGuys\Guzzle\Oauth2\GrantType\AuthorizationCode;
use CommerceGuys\Guzzle\Oauth2\AccessToken;
use CommerceGuys\Guzzle\Oauth2\GrantType\RefreshToken;
use CommerceGuys\Guzzle\Oauth2\Oauth2Subscriber;
use GuzzleHttp\Client as GuzzleClient;
use ConfService;
use AJXP_UserAlertException;
use Exception;
use GuzzleHttp\Event\ErrorEvent;
use GuzzleHttp\Exception\RequestException;

class OAuthWrapper extends AJXP_SchemeTranslatorWrapper
{
/**
* @param $url
* @return bool|void
* @throws AJXP_UserAlertException
* @throws Exception
*/
public static function applyInitPathHook($url) {

// Repository information
$urlParts = AJXP_Utils::safeParseUrl($url);
$repository = ConfService::getRepositoryById($urlParts["host"]);

if ($repository == null) {
throw new Exception("Cannot find repository");
}

$repositoryId = $repository->getId();

if(AuthService::usersEnabled()) {
$u = AuthService::getLoggedUser();
$userId = $u->getId();
if($u->getResolveAsParent()){
$userId = $u->getParent();
}
} else {
$userId = 'shared';
}

// User information

// Repository params
$clientId = $repository->getOption('CLIENT_ID');
$clientSecret = $repository->getOption('CLIENT_SECRET');
$scope = $repository->getOption('SCOPE');
$authUrl = $repository->getOption('AUTH_URL');
$tokenUrl = $repository->getOption('TOKEN_URL');
$redirectUrl = $repository->getOption('REDIRECT_URL');

$authUrl .= '?client_id=' . $clientId .
'&scope=' . $scope .
'&redirect_uri=' . urlencode($redirectUrl) .
'&response_type=code';

// Retrieving context
$repoData = self::actualRepositoryWrapperData($urlParts["host"]);
$repoProtocol = $repoData['protocol'];

$default = stream_context_get_options(stream_context_get_default());

// Retrieving subscriber
$oauth2 = $default[$repoProtocol]['oauth2_subscriber'];

if (!empty($oauth2)) {
// Authentication already made for this request - move on
return true;
}

// Retrieving tokens
$tokensKey = self::getTokenKey($repositoryId, $userId);
$tokens = self::getTokens($tokensKey);

$accessToken = $tokens[0];
$refreshToken = $tokens[1];

// OAuth 2 Tokens
$oauth2Client = new GuzzleClient(['base_url' => $tokenUrl]);

$config = [
'client_id' => $clientId,
'client_secret' => $clientSecret,
'scope' => $scope,
'redirect_uri' => $redirectUrl,
'token_url' => '',
'auth_location' => 'body',
];

// Setting up the subscriber
if (empty($refreshToken) || !empty($_SESSION['oauth_code'])) {
// Authorization code
$config['code'] = $_SESSION['oauth_code'];

$accessToken = new AuthorizationCode($oauth2Client, $config);
$refreshToken = new RefreshToken($oauth2Client, $config);

$oauth2 = new Oauth2Subscriber($accessToken, $refreshToken);

unset($_SESSION['oauth_code']);
} else {
// Refresh Token
$config['refresh_token'] = $refreshToken;

$oauth2 = new Oauth2Subscriber(null, new RefreshToken($oauth2Client, $config));

$oauth2->setAccessToken($accessToken);
$oauth2->setRefreshToken($refreshToken);
}

// Retrieving access token and checking access
try {
$accessToken = $oauth2->getAccessToken();
$refreshToken = $oauth2->getRefreshToken();
} catch (\Exception $e) {
throw new AJXP_UserAlertException("Please go to <a style=\"text-decoration:underline;\" target=\"_blank\" href=\"" . $authUrl . "\">" . $authUrl . "</a> to authorize the access to your onedrive. Then try again to switch to this workspace");
}

// Saving tokens for later use
self::setTokens($tokensKey, $accessToken->getToken(), $refreshToken->getToken());

// Saving subscriber in context
$default[$repoProtocol]['oauth2_subscriber'] = $oauth2;

// Retrieving client
$client = $default[$repoProtocol]['client'];
$httpClient = $client->getHttpClient();
$httpClient->getEmitter()->attach($oauth2);

stream_context_set_default($default);

return true;
}

/**
* @return string key
*/
private static function getTokenKey($repositoryId, $userId) {
return 'OAUTH_ONEDRIVE_' . $repositoryId . '_' . $userId . '_TOKENS';
}
/**
* @return Array
*/
private static function getTokens($key)
{
// TOKENS IN SESSION?
if (!empty($_SESSION[$key])) return $_SESSION[$key];

// TOKENS IN CACHE?
if ($tokens = CacheService::fetch($key)) return $tokens;

// TOKENS IN FILE ?
return AJXP_Utils::loadSerialFile(AJXP_DATA_PATH . '/plugins/access.onedrive/' . $key);
}

/**
* @param $oauth_tokens
* @return bool
* @throws Exception
*/
private function setTokens($key, $accessToken, $refreshToken)
{
$value = [$accessToken, $refreshToken];

// Save in file
AJXP_Utils::saveSerialFile(AJXP_DATA_PATH . '/plugins/access.onedrive/' . $key, $value, true);

// Save in cache
CacheService::save($key, $value);

// Save in session
$_SESSION["OAUTH_ONEDRIVE_TOKENS"] = $value;

return true;
}

}
52 changes: 31 additions & 21 deletions core/src/plugins/core.ajaxplorer/ajxp_mixins.xml
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<ajxp_mixins xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="file:ajxp_registry.xsd">
<credentials_consumer>
<server_settings uuidAttr="name">
<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"/>
<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>
</credentials_consumer>
<slug_provider>
<server_settings uuidAttr="name">
<credentials_consumer>
<server_settings uuidAttr="name">
<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"/>
<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>
</credentials_consumer>
<slug_provider>
<server_settings uuidAttr="name">
<param group="MIXIN_MESSAGE[Repository Commons]" name="USER_DESCRIPTION" type="textarea" label="MIXIN_MESSAGE[Description]" description="MIXIN_MESSAGE[A user-defined description of the content of this workspace]" no_templates="false" default=""/>
<param group="MIXIN_MESSAGE[Repository Commons]" name="DEFAULT_RIGHTS" type="select" choices="r|MIXIN_MESSAGE[Read Only],rw|MIXIN_MESSAGE[Read and Write],w|MIXIN_MESSAGE[Write Only (upload)]" label="MIXIN_MESSAGE[Default Rights]" description="MIXIN_MESSAGE[This right pattern (empty, r, or rw) will be applied at user creation for this repository.]" no_templates="false" default=""/>
<param group="MIXIN_MESSAGE[Repository Commons]" name="AJXP_SLUG" type="string" label="MIXIN_MESSAGE[Alias]" description="MIXIN_MESSAGE[Alias for replacing the generated unique id of the repository]" mandatory="false" no_templates="true"/>
<param group="MIXIN_MESSAGE[Repository Commons]" name="AJXP_GROUP_PATH_PARAMETER" type="string" label="MIXIN_MESSAGE[Group Path]" description="MIXIN_MESSAGE[Set this repository group owner : only users of this group will see it]" mandatory="false" no_templates="true"/>
<param group="MIXIN_MESSAGE[Repository Commons]" name="AJXP_WEBDAV_DISABLED" type="boolean" label="MIXIN_MESSAGE[Disable WebDAV]" description="MIXIN_MESSAGE[Explicitly disable WebDAV access for this repository.]" mandatory="false" default="false" no_templates="true"/>
</server_settings>
</slug_provider>
<template_provider>
<server_settings uuidAttr="name">
<param group="MIXIN_MESSAGE[Template Options]" name="TPL_USER_CAN_CREATE" type="boolean" label="MIXIN_MESSAGE[Allow to user]" description="MIXIN_MESSAGE[Allow non-admin users to create a repository from this template.]" mandatory="true" default="false" templates_only="true"/>
<param group="MIXIN_MESSAGE[Template Options]" name="TPL_GRP_ADMINS_CAN_CREATE" type="boolean" label="MIXIN_MESSAGE[Allow to group admins]" description="MIXIN_MESSAGE[Allow group administrators to create a repository from this template.]" mandatory="true" default="false" templates_only="true"/>
<param group="MIXIN_MESSAGE[Template Options]" name="TPL_DEFAULT_LABEL" type="string" label="MIXIN_MESSAGE[Default Label]" description="MIXIN_MESSAGE[Prefilled label for the new repository, you can use the AJXP_USER keyworkd in it.]" mandatory="true" templates_only="true"/>
<param group="MIXIN_MESSAGE[Repository Commons]" name="AJXP_WEBDAV_DISABLED" type="boolean" label="MIXIN_MESSAGE[Disable WebDAV]" description="MIXIN_MESSAGE[Explicitly disable WebDAV access for this repository.]" mandatory="false" default="false" no_templates="true"/>
</server_settings>
</slug_provider>
<template_provider>
<server_settings uuidAttr="name">
<param group="MIXIN_MESSAGE[Template Options]" name="TPL_USER_CAN_CREATE" type="boolean" label="MIXIN_MESSAGE[Allow to user]" description="MIXIN_MESSAGE[Allow non-admin users to create a repository from this template.]" mandatory="true" default="false" templates_only="true"/>
<param group="MIXIN_MESSAGE[Template Options]" name="TPL_GRP_ADMINS_CAN_CREATE" type="boolean" label="MIXIN_MESSAGE[Allow to group admins]" description="MIXIN_MESSAGE[Allow group administrators to create a repository from this template.]" mandatory="true" default="false" templates_only="true"/>
<param group="MIXIN_MESSAGE[Template Options]" name="TPL_DEFAULT_LABEL" type="string" label="MIXIN_MESSAGE[Default Label]" description="MIXIN_MESSAGE[Prefilled label for the new repository, you can use the AJXP_USER keyworkd in it.]" mandatory="true" templates_only="true"/>
<param group="MIXIN_MESSAGE[Template Options]" name="TPL_ICON_SMALL" type="string" label="MIXIN_MESSAGE[Small Icon]" description="MIXIN_MESSAGE[16X16 Icon for representing the template]" mandatory="false" templates_only="true"/>
<param group="MIXIN_MESSAGE[Template Options]" name="TPL_ICON_BIG" type="string" label="MIXIN_MESSAGE[Big Icon]" description="MIXIN_MESSAGE[Big Icon for representing the template]" mandatory="false" templates_only="true"/>
</server_settings>
</template_provider>
</server_settings>
</template_provider>
<filesystem_commons>
<server_settings uuidAttr="name">
<param group="MIXIN_MESSAGE[Filesystem Commons]" name="RECYCLE_BIN" type="string" label="MIXIN_MESSAGE[Recycle Bin Folder]" description="MIXIN_MESSAGE[Leave empty if you do not want to use a recycle bin.]" default="recycle_bin"/>
Expand Down Expand Up @@ -104,4 +104,14 @@
<global_param group_switch_name="dibi_provider" group_switch_label="MS SQLServer (via mssql extension)" group_switch_value="mssql" name="mssql_password" default="" label="MIXIN_MESSAGE[Password]" description="MIXIN_MESSAGE[User password]" type="password" mandatory="true"/>
</server_settings>
</dibidriver_third_provider>
<oauth_commons>
<server_settings uuidAttr="name">
<param group="MIXIN_MESSAGE[OAuth Commons]" name="CLIENT_ID" type="string" label="MIXIN_MESSAGE[Client ID]" description="MIXIN_MESSAGE[Client ID]" mandatory="true"/>
<param group="MIXIN_MESSAGE[OAuth Commons]" name="CLIENT_SECRET" type="string" label="MIXIN_MESSAGE[Client SECRET]" description="MIXIN_MESSAGE[Client SECRET]" mandatory="true"/>
<param group="MIXIN_MESSAGE[OAuth Commons]" name="SCOPE" type="string" label="MIXIN_MESSAGE[Scope]" description="MIXIN_MESSAGE[Scope]" mandatory="true"/>
<param group="MIXIN_MESSAGE[OAuth Commons]" name="AUTH_URL" type="string" label="MIXIN_MESSAGE[Auth URL]" description="MIXIN_MESSAGE[API endpoint - Used to launch the window allowing the user to authenticate and accept the terms of the app]" mandatory="true"/>
<param group="MIXIN_MESSAGE[OAuth Commons]" name="TOKEN_URL" type="string" label="MIXIN_MESSAGE[Token URL]" description="MIXIN_MESSAGE[API endpoint - Used to refresh or validate the token retrieved in the authentication part]" mandatory="true"/>
<param group="MIXIN_MESSAGE[OAuth Commons]" name="REDIRECT_URL" type="string" label="MIXIN_MESSAGE[Redirect URL]" description="MIXIN_MESSAGE[API setting - Redirect URL for the OAuth Application]" mandatory="true"/>
</server_settings>
</oauth_commons>
</ajxp_mixins>
2 changes: 1 addition & 1 deletion core/src/plugins/core.ajaxplorer/ajxp_registry.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,7 @@
</xs:element>
<xs:element name="class_stream_wrapper">
<xs:complexType>
<xs:attribute name="classname" use="required" type="xs:NCName"/>
<xs:attribute name="classname" use="required" type="xs:string"/>
<xs:attribute name="filename" use="required"/>
<xs:attribute name="protocol" use="required" type="xs:NCName"/>
</xs:complexType>
Expand Down
10 changes: 10 additions & 0 deletions core/src/plugins/core.ajaxplorer/i18n/conf/de.php
Original file line number Diff line number Diff line change
Expand Up @@ -176,4 +176,14 @@
"Read Only" => "Nur Lesen",
"Read and Write" => "Lesen und Schreiben",
"Write Only (upload)" => "Nur Schreiben (hochladen)",
"OAuth Commons" => "OAuth Commons",
"Client ID" => "Client ID",
"Client SECRET" => "Client SECRET",
"Scope" => "Scope",
"Auth URL" => "Auth URL",
"Token URL" => "Token URL",
"Redirect URL" => "Redirect URL",
"API endpoint - Used to launch the window allowing the user to authenticate and accept the terms of the app" => "API endpoint - Used to launch the window allowing the user to authenticate and accept the terms of the app",
"API endpoint - Used to refresh or validate the token retrieved in the authentication part" => "API endpoint - Used to refresh or validate the token retrieved in the authentication part",
"API setting - Redirect URL for the OAuth Application" => "API setting - Redirect URL for the OAuth Application"
);
10 changes: 10 additions & 0 deletions core/src/plugins/core.ajaxplorer/i18n/conf/en.php
Original file line number Diff line number Diff line change
Expand Up @@ -167,4 +167,14 @@
"Read Only" => "Read Only",
"Read and Write" => "Read and Write",
"Write Only (upload)" => "Write Only (upload)",
"OAuth Commons" => "OAuth Commons",
"Client ID" => "Client ID",
"Client SECRET" => "Client SECRET",
"Scope" => "Scope",
"Auth URL" => "Auth URL",
"Token URL" => "Token URL",
"Redirect URL" => "Redirect URL",
"API endpoint - Used to launch the window allowing the user to authenticate and accept the terms of the app" => "API endpoint - Used to launch the window allowing the user to authenticate and accept the terms of the app",
"API endpoint - Used to refresh or validate the token retrieved in the authentication part" => "API endpoint - Used to refresh or validate the token retrieved in the authentication part",
"API setting - Redirect URL for the OAuth Application" => "API setting - Redirect URL for the OAuth Application"
);
10 changes: 10 additions & 0 deletions core/src/plugins/core.ajaxplorer/i18n/conf/fr.php
Original file line number Diff line number Diff line change
Expand Up @@ -168,4 +168,14 @@
"Read Only" => "Read Only",
"Read and Write" => "Read and Write",
"Write Only (upload)" => "Write Only (upload)",
"OAuth Commons" => "Paramètres Communs OAuth",
"Client ID" => "Client ID",
"Client SECRET" => "Client SECRET",
"Scope" => "Scope",
"Auth URL" => "URL d'autorisation",
"Token URL" => "URL du 'Refresh Token'",
"Redirect URL" => "URL de redirection",
"API endpoint - Used to launch the window allowing the user to authenticate and accept the terms of the app" => "Point final de l'API endpoint - Ouvre la fenêtre permettant à l'utilisateur de s'authentifier et d'accepter les termes de l'application",
"API endpoint - Used to refresh or validate the token retrieved in the authentication part" => "API endpoint - Rafraîchit ou valide le token reçu pendant l'authentification",
"API setting - Redirect URL for the OAuth Application" => "API setting - Url de redirection de l'application OAuth"
);
10 changes: 10 additions & 0 deletions core/src/plugins/core.ajaxplorer/i18n/conf/it.php
Original file line number Diff line number Diff line change
Expand Up @@ -169,4 +169,14 @@
"Read Only" => "Read Only",
"Read and Write" => "Read and Write",
"Write Only (upload)" => "Write Only (upload)",
"OAuth Commons" => "OAuth Commons",
"Client ID" => "Client ID",
"Client SECRET" => "Client SECRET",
"Scope" => "Scope",
"Auth URL" => "Auth URL",
"Token URL" => "Token URL",
"Redirect URL" => "Redirect URL",
"API endpoint - Used to launch the window allowing the user to authenticate and accept the terms of the app" => "API endpoint - Used to launch the window allowing the user to authenticate and accept the terms of the app",
"API endpoint - Used to refresh or validate the token retrieved in the authentication part" => "API endpoint - Used to refresh or validate the token retrieved in the authentication part",
"API setting - Redirect URL for the OAuth Application" => "API setting - Redirect URL for the OAuth Application"
);
Loading

0 comments on commit 5f1be52

Please sign in to comment.