Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F542421
PhabricatorAuthLoginController.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
PhabricatorAuthLoginController.php
View Options
<?php
final
class
PhabricatorAuthLoginController
extends
PhabricatorAuthController
{
private
$providerKey
;
private
$extraURIData
;
private
$provider
;
public
function
shouldRequireLogin
()
{
return
false
;
}
public
function
shouldAllowRestrictedParameter
(
$parameter_name
)
{
// Whitelist the OAuth 'code' parameter.
if
(
$parameter_name
==
'code'
)
{
return
true
;
}
return
parent
::
shouldAllowRestrictedParameter
(
$parameter_name
);
}
public
function
getExtraURIData
()
{
return
$this
->
extraURIData
;
}
public
function
handleRequest
(
AphrontRequest
$request
)
{
$viewer
=
$this
->
getViewer
();
$this
->
providerKey
=
$request
->
getURIData
(
'pkey'
);
$this
->
extraURIData
=
$request
->
getURIData
(
'extra'
);
$response
=
$this
->
loadProvider
();
if
(
$response
)
{
return
$response
;
}
$invite
=
$this
->
loadInvite
();
$provider
=
$this
->
provider
;
try
{
list
(
$account
,
$response
)
=
$provider
->
processLoginRequest
(
$this
);
}
catch
(
PhutilAuthUserAbortedException
$ex
)
{
if
(
$viewer
->
isLoggedIn
())
{
// If a logged-in user cancels, take them back to the external accounts
// panel.
$next_uri
=
'/settings/panel/external/'
;
}
else
{
// If a logged-out user cancels, take them back to the auth start page.
$next_uri
=
'/'
;
}
// User explicitly hit "Cancel".
$dialog
=
id
(
new
AphrontDialogView
())
->
setUser
(
$viewer
)
->
setTitle
(
pht
(
'Authentication Canceled'
))
->
appendChild
(
pht
(
'You canceled authentication.'
))
->
addCancelButton
(
$next_uri
,
pht
(
'Continue'
));
return
id
(
new
AphrontDialogResponse
())->
setDialog
(
$dialog
);
}
if
(
$response
)
{
return
$response
;
}
if
(!
$account
)
{
throw
new
Exception
(
pht
(
'Auth provider failed to load an account from %s!'
,
'processLoginRequest()'
));
}
if
(
$account
->
getUserPHID
())
{
// The account is already attached to a Phabricator user, so this is
// either a login or a bad account link request.
if
(!
$viewer
->
isLoggedIn
())
{
if
(
$provider
->
shouldAllowLogin
())
{
return
$this
->
processLoginUser
(
$account
);
}
else
{
return
$this
->
renderError
(
pht
(
'The external service ("%s") you just authenticated with is '
.
'not configured to allow logins on this server. An '
.
'administrator may have recently disabled it.'
,
$provider
->
getProviderName
()));
}
}
else
if
(
$viewer
->
getPHID
()
==
$account
->
getUserPHID
())
{
// This is either an attempt to re-link an existing and already
// linked account (which is silly) or a refresh of an external account
// (e.g., an OAuth account).
return
id
(
new
AphrontRedirectResponse
())
->
setURI
(
'/settings/panel/external/'
);
}
else
{
return
$this
->
renderError
(
pht
(
'The external service ("%s") you just used to log in is already '
.
'associated with another %s user account. Log in to the '
.
'other %s account and unlink the external account before '
.
'linking it to a new %s account.'
,
$provider
->
getProviderName
(),
PlatformSymbols
::
getPlatformServerName
(),
PlatformSymbols
::
getPlatformServerName
(),
PlatformSymbols
::
getPlatformServerName
()));
}
}
else
{
// The account is not yet attached to a Phabricator user, so this is
// either a registration or an account link request.
if
(!
$viewer
->
isLoggedIn
())
{
if
(
$provider
->
shouldAllowRegistration
()
||
$invite
)
{
return
$this
->
processRegisterUser
(
$account
);
}
else
{
return
$this
->
renderError
(
pht
(
'The external service ("%s") you just authenticated with is '
.
'not configured to allow registration on this server. An '
.
'administrator may have recently disabled it.'
,
$provider
->
getProviderName
()));
}
}
else
{
// If the user already has a linked account on this provider, prevent
// them from linking a second account. This can happen if they swap
// logins and then refresh the account link.
// There's no technical reason we can't allow you to link multiple
// accounts from a single provider; disallowing this is currently a
// product deciison. See T2549.
$existing_accounts
=
id
(
new
PhabricatorExternalAccountQuery
())
->
setViewer
(
$viewer
)
->
withUserPHIDs
(
array
(
$viewer
->
getPHID
()))
->
withProviderConfigPHIDs
(
array
(
$provider
->
getProviderConfigPHID
(),
))
->
execute
();
if
(
$existing_accounts
)
{
return
$this
->
renderError
(
pht
(
'Your %s account is already connected to an external '
.
'account on this service ("%s"), but you are currently logged '
.
'in to the service with a different account. Log out of the '
.
'external service, then log back in with the correct account '
.
'before refreshing the account link.'
,
PlatformSymbols
::
getPlatformServerName
(),
$provider
->
getProviderName
()));
}
if
(
$provider
->
shouldAllowAccountLink
())
{
return
$this
->
processLinkUser
(
$account
);
}
else
{
return
$this
->
renderError
(
pht
(
'The external service ("%s") you just authenticated with is '
.
'not configured to allow account linking on this server. An '
.
'administrator may have recently disabled it.'
,
$provider
->
getProviderName
()));
}
}
}
// This should be unreachable, but fail explicitly if we get here somehow.
return
new
Aphront400Response
();
}
private
function
processLoginUser
(
PhabricatorExternalAccount
$account
)
{
$user
=
id
(
new
PhabricatorUser
())->
loadOneWhere
(
'phid = %s'
,
$account
->
getUserPHID
());
if
(!
$user
)
{
return
$this
->
renderError
(
pht
(
'The external account you just logged in with is not associated '
.
'with a valid %s user account.'
,
PlatformSymbols
::
getPlatformServerName
()));
}
return
$this
->
loginUser
(
$user
);
}
private
function
processRegisterUser
(
PhabricatorExternalAccount
$account
)
{
$account_secret
=
$account
->
getAccountSecret
();
$register_uri
=
$this
->
getApplicationURI
(
'register/'
.
$account_secret
.
'/'
);
return
$this
->
setAccountKeyAndContinue
(
$account
,
$register_uri
);
}
private
function
processLinkUser
(
PhabricatorExternalAccount
$account
)
{
$account_secret
=
$account
->
getAccountSecret
();
$confirm_uri
=
$this
->
getApplicationURI
(
'confirmlink/'
.
$account_secret
.
'/'
);
return
$this
->
setAccountKeyAndContinue
(
$account
,
$confirm_uri
);
}
private
function
setAccountKeyAndContinue
(
PhabricatorExternalAccount
$account
,
$next_uri
)
{
if
(
$account
->
getUserPHID
())
{
throw
new
Exception
(
pht
(
'Account is already registered or linked.'
));
}
// Regenerate the registration secret key, set it on the external account,
// set a cookie on the user's machine, and redirect them to registration.
// See PhabricatorAuthRegisterController for discussion of the registration
// key.
$registration_key
=
Filesystem
::
readRandomCharacters
(
32
);
$account
->
setProperty
(
'registrationKey'
,
PhabricatorHash
::
weakDigest
(
$registration_key
));
$unguarded
=
AphrontWriteGuard
::
beginScopedUnguardedWrites
();
$account
->
save
();
unset
(
$unguarded
);
$this
->
getRequest
()->
setTemporaryCookie
(
PhabricatorCookies
::
COOKIE_REGISTRATION
,
$registration_key
);
return
id
(
new
AphrontRedirectResponse
())->
setURI
(
$next_uri
);
}
private
function
loadProvider
()
{
$provider
=
PhabricatorAuthProvider
::
getEnabledProviderByKey
(
$this
->
providerKey
);
if
(!
$provider
)
{
return
$this
->
renderError
(
pht
(
'The account you are attempting to log in with uses a nonexistent '
.
'or disabled authentication provider (with key "%s"). An '
.
'administrator may have recently disabled this provider.'
,
$this
->
providerKey
));
}
$this
->
provider
=
$provider
;
return
null
;
}
protected
function
renderError
(
$message
)
{
return
$this
->
renderErrorPage
(
pht
(
'Login Failed'
),
array
(
$message
));
}
public
function
buildProviderPageResponse
(
PhabricatorAuthProvider
$provider
,
$content
)
{
$crumbs
=
$this
->
buildApplicationCrumbs
();
$viewer
=
$this
->
getViewer
();
if
(
$viewer
->
isLoggedIn
())
{
$crumbs
->
addTextCrumb
(
pht
(
'Link Account'
),
$provider
->
getSettingsURI
());
}
else
{
$crumbs
->
addTextCrumb
(
pht
(
'Login'
),
$this
->
getApplicationURI
(
'start/'
));
$content
=
array
(
$this
->
newCustomStartMessage
(),
$content
,
);
}
$crumbs
->
addTextCrumb
(
$provider
->
getProviderName
());
$crumbs
->
setBorder
(
true
);
return
$this
->
newPage
()
->
setTitle
(
pht
(
'Login'
))
->
setCrumbs
(
$crumbs
)
->
appendChild
(
$content
);
}
public
function
buildProviderErrorResponse
(
PhabricatorAuthProvider
$provider
,
$message
)
{
$message
=
pht
(
'Authentication provider ("%s") encountered an error while attempting '
.
'to log in. %s'
,
$provider
->
getProviderName
(),
$message
);
return
$this
->
renderError
(
$message
);
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Mon, May 12, 10:42 AM (2 d)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
103556
Default Alt Text
PhabricatorAuthLoginController.php (9 KB)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment