Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F93117403
PhabricatorOAuth2AuthProvider.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Tue, Nov 26, 08:19
Size
7 KB
Mime Type
text/x-php
Expires
Thu, Nov 28, 08:19 (2 d)
Engine
blob
Format
Raw Data
Handle
22578500
Attached To
rPH Phabricator
PhabricatorOAuth2AuthProvider.php
View Options
<?php
abstract
class
PhabricatorOAuth2AuthProvider
extends
PhabricatorOAuthAuthProvider
{
const
PROPERTY_APP_ID
=
'oauth:app:id'
;
const
PROPERTY_APP_SECRET
=
'oauth:app:secret'
;
protected
function
getIDKey
()
{
return
self
::
PROPERTY_APP_ID
;
}
protected
function
getSecretKey
()
{
return
self
::
PROPERTY_APP_SECRET
;
}
protected
function
configureAdapter
(
PhutilOAuthAuthAdapter
$adapter
)
{
$config
=
$this
->
getProviderConfig
();
$adapter
->
setClientID
(
$config
->
getProperty
(
self
::
PROPERTY_APP_ID
));
$adapter
->
setClientSecret
(
new
PhutilOpaqueEnvelope
(
$config
->
getProperty
(
self
::
PROPERTY_APP_SECRET
)));
$adapter
->
setRedirectURI
(
PhabricatorEnv
::
getURI
(
$this
->
getLoginURI
()));
return
$adapter
;
}
protected
function
renderLoginForm
(
AphrontRequest
$request
,
$mode
)
{
$adapter
=
$this
->
getAdapter
();
$adapter
->
setState
(
$this
->
getAuthCSRFCode
(
$request
));
$scope
=
$request
->
getStr
(
'scope'
);
if
(
$scope
)
{
$adapter
->
setScope
(
$scope
);
}
$attributes
=
array
(
'method'
=>
'GET'
,
'uri'
=>
$adapter
->
getAuthenticateURI
(),
);
return
$this
->
renderStandardLoginButton
(
$request
,
$mode
,
$attributes
);
}
public
function
processLoginRequest
(
PhabricatorAuthLoginController
$controller
)
{
$request
=
$controller
->
getRequest
();
$adapter
=
$this
->
getAdapter
();
$account
=
null
;
$response
=
null
;
$error
=
$request
->
getStr
(
'error'
);
if
(
$error
)
{
$response
=
$controller
->
buildProviderErrorResponse
(
$this
,
pht
(
'The OAuth provider returned an error: %s'
,
$error
));
return
array
(
$account
,
$response
);
}
$this
->
verifyAuthCSRFCode
(
$request
,
$request
->
getStr
(
'state'
));
$code
=
$request
->
getStr
(
'code'
);
if
(!
strlen
(
$code
))
{
$response
=
$controller
->
buildProviderErrorResponse
(
$this
,
pht
(
'The OAuth provider did not return a "code" parameter in its '
.
'response.'
));
return
array
(
$account
,
$response
);
}
$adapter
->
setCode
(
$code
);
// NOTE: As a side effect, this will cause the OAuth adapter to request
// an access token.
try
{
$account_id
=
$adapter
->
getAccountID
();
}
catch
(
Exception
$ex
)
{
// TODO: Handle this in a more user-friendly way.
throw
$ex
;
}
if
(!
strlen
(
$account_id
))
{
$response
=
$controller
->
buildProviderErrorResponse
(
$this
,
pht
(
'The OAuth provider failed to retrieve an account ID.'
));
return
array
(
$account
,
$response
);
}
return
array
(
$this
->
loadOrCreateAccount
(
$account_id
),
$response
);
}
public
function
processEditForm
(
AphrontRequest
$request
,
array
$values
)
{
return
$this
->
processOAuthEditForm
(
$request
,
$values
,
pht
(
'Application ID is required.'
),
pht
(
'Application secret is required.'
));
}
public
function
extendEditForm
(
AphrontRequest
$request
,
AphrontFormView
$form
,
array
$values
,
array
$issues
)
{
return
$this
->
extendOAuthEditForm
(
$request
,
$form
,
$values
,
$issues
,
pht
(
'OAuth App ID'
),
pht
(
'OAuth App Secret'
));
}
public
function
renderConfigPropertyTransactionTitle
(
PhabricatorAuthProviderConfigTransaction
$xaction
)
{
$author_phid
=
$xaction
->
getAuthorPHID
();
$old
=
$xaction
->
getOldValue
();
$new
=
$xaction
->
getNewValue
();
$key
=
$xaction
->
getMetadataValue
(
PhabricatorAuthProviderConfigTransaction
::
PROPERTY_KEY
);
switch
(
$key
)
{
case
self
::
PROPERTY_APP_ID
:
if
(
strlen
(
$old
))
{
return
pht
(
'%s updated the OAuth application ID for this provider from '
.
'"%s" to "%s".'
,
$xaction
->
renderHandleLink
(
$author_phid
),
$old
,
$new
);
}
else
{
return
pht
(
'%s set the OAuth application ID for this provider to '
.
'"%s".'
,
$xaction
->
renderHandleLink
(
$author_phid
),
$new
);
}
case
self
::
PROPERTY_APP_SECRET
:
if
(
strlen
(
$old
))
{
return
pht
(
'%s updated the OAuth application secret for this provider.'
,
$xaction
->
renderHandleLink
(
$author_phid
));
}
else
{
return
pht
(
'%s set the OAuth application secret for this provider.'
,
$xaction
->
renderHandleLink
(
$author_phid
));
}
case
self
::
PROPERTY_NOTE
:
if
(
strlen
(
$old
))
{
return
pht
(
'%s updated the OAuth application notes for this provider.'
,
$xaction
->
renderHandleLink
(
$author_phid
));
}
else
{
return
pht
(
'%s set the OAuth application notes for this provider.'
,
$xaction
->
renderHandleLink
(
$author_phid
));
}
}
return
parent
::
renderConfigPropertyTransactionTitle
(
$xaction
);
}
protected
function
synchronizeOAuthAccount
(
PhabricatorExternalAccount
$account
)
{
$adapter
=
$this
->
getAdapter
();
$oauth_token
=
$adapter
->
getAccessToken
();
$account
->
setProperty
(
'oauth.token.access'
,
$oauth_token
);
if
(
$adapter
->
supportsTokenRefresh
())
{
$refresh_token
=
$adapter
->
getRefreshToken
();
$account
->
setProperty
(
'oauth.token.refresh'
,
$refresh_token
);
}
else
{
$account
->
setProperty
(
'oauth.token.refresh'
,
null
);
}
$expires
=
$adapter
->
getAccessTokenExpires
();
$account
->
setProperty
(
'oauth.token.access.expires'
,
$expires
);
}
public
function
getOAuthAccessToken
(
PhabricatorExternalAccount
$account
,
$force_refresh
=
false
)
{
if
(
$account
->
getProviderKey
()
!==
$this
->
getProviderKey
())
{
throw
new
Exception
(
pht
(
'Account does not match provider!'
));
}
if
(!
$force_refresh
)
{
$access_expires
=
$account
->
getProperty
(
'oauth.token.access.expires'
);
$access_token
=
$account
->
getProperty
(
'oauth.token.access'
);
// Don't return a token with fewer than this many seconds remaining until
// it expires.
$shortest_token
=
60
;
if
(
$access_token
)
{
if
(
$access_expires
===
null
||
$access_expires
>
(
time
()
+
$shortest_token
))
{
return
$access_token
;
}
}
}
$refresh_token
=
$account
->
getProperty
(
'oauth.token.refresh'
);
if
(
$refresh_token
)
{
$adapter
=
$this
->
getAdapter
();
if
(
$adapter
->
supportsTokenRefresh
())
{
$adapter
->
refreshAccessToken
(
$refresh_token
);
$this
->
synchronizeOAuthAccount
(
$account
);
$unguarded
=
AphrontWriteGuard
::
beginScopedUnguardedWrites
();
$account
->
save
();
unset
(
$unguarded
);
return
$account
->
getProperty
(
'oauth.token.access'
);
}
}
return
null
;
}
public
function
willRenderLinkedAccount
(
PhabricatorUser
$viewer
,
PHUIObjectItemView
$item
,
PhabricatorExternalAccount
$account
)
{
// Get a valid token, possibly refreshing it. If we're unable to refresh
// it, render a message to that effect. The user may be able to repair the
// link by manually reconnecting.
$is_invalid
=
false
;
try
{
$oauth_token
=
$this
->
getOAuthAccessToken
(
$account
);
}
catch
(
Exception
$ex
)
{
$oauth_token
=
null
;
$is_invalid
=
true
;
}
$item
->
addAttribute
(
pht
(
'OAuth2 Account'
));
if
(
$oauth_token
)
{
$oauth_expires
=
$account
->
getProperty
(
'oauth.token.access.expires'
);
if
(
$oauth_expires
)
{
$item
->
addAttribute
(
pht
(
'Active OAuth Token (Expires: %s)'
,
phabricator_datetime
(
$oauth_expires
,
$viewer
)));
}
else
{
$item
->
addAttribute
(
pht
(
'Active OAuth Token'
));
}
}
else
if
(
$is_invalid
)
{
$item
->
addAttribute
(
pht
(
'Invalid OAuth Access Token'
));
}
else
{
$item
->
addAttribute
(
pht
(
'No OAuth Access Token'
));
}
parent
::
willRenderLinkedAccount
(
$viewer
,
$item
,
$account
);
}
}
Event Timeline
Log In to Comment