mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-27 01:02:42 +01:00
Make Oauth-registration flows a bit more resilient to failures from the providers
Summary: basically by validating we have good user data when we set the user data. Test Plan: simulated a failure from a phabricator on phabricator oauth scenario. viewed ui that correctly told me there was an error with the provider and to try again. Reviewers: epriestley Reviewed By: epriestley CC: aran, Koolvin Maniphest Tasks: T1077 Differential Revision: https://secure.phabricator.com/D2337
This commit is contained in:
parent
458563c68a
commit
8988667dcc
13 changed files with 77 additions and 11 deletions
|
@ -713,6 +713,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorOAuthFailureView' => 'applications/auth/view/oauthfailure',
|
'PhabricatorOAuthFailureView' => 'applications/auth/view/oauthfailure',
|
||||||
'PhabricatorOAuthLoginController' => 'applications/auth/controller/oauth',
|
'PhabricatorOAuthLoginController' => 'applications/auth/controller/oauth',
|
||||||
'PhabricatorOAuthProvider' => 'applications/auth/oauth/provider/base',
|
'PhabricatorOAuthProvider' => 'applications/auth/oauth/provider/base',
|
||||||
|
'PhabricatorOAuthProviderException' => 'applications/auth/oauth/provider/exception',
|
||||||
'PhabricatorOAuthProviderFacebook' => 'applications/auth/oauth/provider/facebook',
|
'PhabricatorOAuthProviderFacebook' => 'applications/auth/oauth/provider/facebook',
|
||||||
'PhabricatorOAuthProviderGitHub' => 'applications/auth/oauth/provider/github',
|
'PhabricatorOAuthProviderGitHub' => 'applications/auth/oauth/provider/github',
|
||||||
'PhabricatorOAuthProviderGoogle' => 'applications/auth/oauth/provider/google',
|
'PhabricatorOAuthProviderGoogle' => 'applications/auth/oauth/provider/google',
|
||||||
|
|
|
@ -64,8 +64,12 @@ final class PhabricatorOAuthLoginController
|
||||||
'access_token' => $this->accessToken,
|
'access_token' => $this->accessToken,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
try {
|
||||||
$user_data = @file_get_contents($userinfo_uri);
|
$user_data = @file_get_contents($userinfo_uri);
|
||||||
$provider->setUserData($user_data);
|
$provider->setUserData($user_data);
|
||||||
|
} catch (PhabricatorOAuthProviderException $e) {
|
||||||
|
return $this->buildErrorResponse(new PhabricatorOAuthFailureView());
|
||||||
|
}
|
||||||
$provider->setAccessToken($this->accessToken);
|
$provider->setAccessToken($this->accessToken);
|
||||||
|
|
||||||
$user_id = $provider->retrieveUserID();
|
$user_id = $provider->retrieveUserID();
|
||||||
|
|
|
@ -98,6 +98,19 @@ abstract class PhabricatorOAuthProvider {
|
||||||
return $this->accessToken;
|
return $this->accessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Often used within setUserData to make sure $data is not completely
|
||||||
|
* junk. More granular validations of data might be necessary depending on
|
||||||
|
* the provider and are generally encouraged.
|
||||||
|
*/
|
||||||
|
final protected function validateUserData($data) {
|
||||||
|
if (empty($data) || !is_array($data)) {
|
||||||
|
throw new PhabricatorOAuthProviderException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public static function newProvider($which) {
|
public static function newProvider($which) {
|
||||||
switch ($which) {
|
switch ($which) {
|
||||||
case self::PROVIDER_FACEBOOK:
|
case self::PROVIDER_FACEBOOK:
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_module('phabricator', 'applications/auth/oauth/provider/exception');
|
||||||
phutil_require_module('phabricator', 'infrastructure/env');
|
phutil_require_module('phabricator', 'infrastructure/env');
|
||||||
|
|
||||||
phutil_require_module('phutil', 'symbols');
|
phutil_require_module('phutil', 'symbols');
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2012 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
final class PhabricatorOAuthProviderException extends Exception {
|
||||||
|
}
|
10
src/applications/auth/oauth/provider/exception/__init__.php
Normal file
10
src/applications/auth/oauth/provider/exception/__init__.php
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is automatically generated. Lint this module to rebuild it.
|
||||||
|
* @generated
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_source('PhabricatorOAuthProviderException.php');
|
|
@ -82,7 +82,9 @@ final class PhabricatorOAuthProviderFacebook extends PhabricatorOAuthProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setUserData($data) {
|
public function setUserData($data) {
|
||||||
$this->userData = json_decode($data, true);
|
$data = json_decode($data, true);
|
||||||
|
$this->validateUserData($data);
|
||||||
|
$this->userData = $data;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,9 @@ final class PhabricatorOAuthProviderGitHub extends PhabricatorOAuthProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setUserData($data) {
|
public function setUserData($data) {
|
||||||
$this->userData = idx(json_decode($data, true), 'user');
|
$data = idx(json_decode($data, true), 'user');
|
||||||
|
$this->validateUserData($data);
|
||||||
|
$this->userData = $data;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,14 @@ final class PhabricatorOAuthProviderGoogle extends PhabricatorOAuthProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setUserData($data) {
|
public function setUserData($data) {
|
||||||
|
// SimpleXMLElement will throw if $data is unusably malformed, which to
|
||||||
|
// us is just a provider issue
|
||||||
|
try {
|
||||||
$xml = new SimpleXMLElement($data);
|
$xml = new SimpleXMLElement($data);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
throw new PhabricatorOAuthProviderException();
|
||||||
|
}
|
||||||
|
|
||||||
$id = (string)$xml->id;
|
$id = (string)$xml->id;
|
||||||
$this->userData = array(
|
$this->userData = array(
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
|
|
||||||
phutil_require_module('phabricator', 'applications/auth/oauth/provider/base');
|
phutil_require_module('phabricator', 'applications/auth/oauth/provider/base');
|
||||||
|
phutil_require_module('phabricator', 'applications/auth/oauth/provider/exception');
|
||||||
phutil_require_module('phabricator', 'infrastructure/env');
|
phutil_require_module('phabricator', 'infrastructure/env');
|
||||||
|
|
||||||
phutil_require_module('phutil', 'utils');
|
phutil_require_module('phutil', 'utils');
|
||||||
|
|
|
@ -102,11 +102,9 @@ extends PhabricatorOAuthProvider {
|
||||||
public function setUserData($data) {
|
public function setUserData($data) {
|
||||||
// need to strip the javascript shield from conduit
|
// need to strip the javascript shield from conduit
|
||||||
$data = substr($data, 8);
|
$data = substr($data, 8);
|
||||||
$data = json_decode($data, true);
|
$data = idx(json_decode($data, true), 'result');
|
||||||
if (!is_array($data)) {
|
$this->validateUserData($data);
|
||||||
throw new Exception('Invalid user data.');
|
$this->userData = $data;
|
||||||
}
|
|
||||||
$this->userData = $data['result'];
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,5 +9,7 @@
|
||||||
phutil_require_module('phabricator', 'applications/auth/oauth/provider/base');
|
phutil_require_module('phabricator', 'applications/auth/oauth/provider/base');
|
||||||
phutil_require_module('phabricator', 'infrastructure/env');
|
phutil_require_module('phabricator', 'infrastructure/env');
|
||||||
|
|
||||||
|
phutil_require_module('phutil', 'utils');
|
||||||
|
|
||||||
|
|
||||||
phutil_require_source('PhabricatorOAuthProviderPhabricator.php');
|
phutil_require_source('PhabricatorOAuthProviderPhabricator.php');
|
||||||
|
|
|
@ -226,8 +226,13 @@ final class PhabricatorUserOAuthSettingsPanelController
|
||||||
$error = 'Unable to retrieve image.';
|
$error = 'Unable to retrieve image.';
|
||||||
}
|
}
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
if ($e instanceof PhabricatorOAuthProviderException) {
|
||||||
|
$error = sprintf('Unable to retrieve image from %s',
|
||||||
|
$provider->getProviderName());
|
||||||
|
} else {
|
||||||
$error = 'Unable to save image.';
|
$error = 'Unable to save image.';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
$notice = new AphrontErrorView();
|
$notice = new AphrontErrorView();
|
||||||
if ($error) {
|
if ($error) {
|
||||||
$notice
|
$notice
|
||||||
|
|
Loading…
Reference in a new issue