2012-08-05 14:12:43 -07:00
|
|
|
<?php
|
|
|
|
|
|
|
|
final class PhabricatorApplicationAuth extends PhabricatorApplication {
|
|
|
|
|
2013-01-29 09:14:03 -08:00
|
|
|
public function canUninstall() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-16 10:15:16 -07:00
|
|
|
public function getBaseURI() {
|
|
|
|
return '/auth/';
|
|
|
|
}
|
|
|
|
|
2013-06-18 10:02:34 -07:00
|
|
|
public function getIconName() {
|
|
|
|
return 'authentication';
|
|
|
|
}
|
|
|
|
|
2013-06-20 11:18:48 -07:00
|
|
|
public function getHelpURI() {
|
|
|
|
// NOTE: Although reasonable help exists for this in "Configuring Accounts
|
|
|
|
// and Registration", specifying a help URI here means we get the menu
|
|
|
|
// item in all the login/link interfaces, which is confusing and not
|
|
|
|
// helpful.
|
|
|
|
|
|
|
|
// TODO: Special case this, or split the auth and auth administration
|
|
|
|
// applications?
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2012-08-05 14:12:43 -07:00
|
|
|
public function buildMainMenuItems(
|
|
|
|
PhabricatorUser $user,
|
2012-08-06 12:46:51 -07:00
|
|
|
PhabricatorController $controller = null) {
|
2012-08-05 14:12:43 -07:00
|
|
|
|
|
|
|
$items = array();
|
|
|
|
|
2012-08-10 12:11:24 -07:00
|
|
|
if ($user->isLoggedIn()) {
|
2013-06-18 11:05:28 -07:00
|
|
|
$item = id(new PHUIListItemView())
|
|
|
|
->addClass('core-menu-item')
|
|
|
|
->setName(pht('Log Out'))
|
2014-01-31 09:10:32 -08:00
|
|
|
->setIcon('logout-sm')
|
2013-06-18 11:05:28 -07:00
|
|
|
->setWorkflow(true)
|
|
|
|
->setHref('/logout/')
|
2014-01-28 20:18:01 -08:00
|
|
|
->setSelected(($controller instanceof PhabricatorLogoutController))
|
Add support for aural-only and visual-only elements
Summary:
Ref T4843. This adds support to `javelin_tag()` for an `aural` attribute. When specified, `true` values mean "this content is aural-only", while `false` values mean "this content is not aural".
- I've attempted to find the best modern approaches for marking this content, but the `aural` attribute should let us change the mechanism later.
- Make the "beta" markers on application navigation visual only (see T4843). This information is of very low importance, the application navigation is accessed frequently, and the information is available on the application list.
- Partially convert the main navigation. This is mostly to test things, since I want to get more concrete feedback about approaches here.
- Add a `?__aural__=1` attribute, which renders the page with aural-only elements visible and visual-only elements colored.
Test Plan: {F146476}
Reviewers: btrahan, scp, chad
Reviewed By: chad
Subscribers: aklapper, qgil, epriestley
Maniphest Tasks: T4843
Differential Revision: https://secure.phabricator.com/D8830
2014-05-01 07:18:18 -07:00
|
|
|
->setAural(pht('Log Out'))
|
2014-01-28 20:18:01 -08:00
|
|
|
->setOrder(900);
|
2012-08-05 14:12:43 -07:00
|
|
|
$items[] = $item;
|
2013-11-13 11:24:38 -08:00
|
|
|
} else {
|
|
|
|
if ($controller instanceof PhabricatorAuthController) {
|
|
|
|
// Don't show the "Login" item on auth controllers, since they're
|
|
|
|
// generally all related to logging in anyway.
|
|
|
|
} else {
|
|
|
|
$item = id(new PHUIListItemView())
|
|
|
|
->addClass('core-menu-item')
|
|
|
|
->setName(pht('Log In'))
|
|
|
|
// TODO: Login icon?
|
|
|
|
->setIcon('power')
|
2014-01-28 20:18:01 -08:00
|
|
|
->setHref('/auth/start/')
|
Add support for aural-only and visual-only elements
Summary:
Ref T4843. This adds support to `javelin_tag()` for an `aural` attribute. When specified, `true` values mean "this content is aural-only", while `false` values mean "this content is not aural".
- I've attempted to find the best modern approaches for marking this content, but the `aural` attribute should let us change the mechanism later.
- Make the "beta" markers on application navigation visual only (see T4843). This information is of very low importance, the application navigation is accessed frequently, and the information is available on the application list.
- Partially convert the main navigation. This is mostly to test things, since I want to get more concrete feedback about approaches here.
- Add a `?__aural__=1` attribute, which renders the page with aural-only elements visible and visual-only elements colored.
Test Plan: {F146476}
Reviewers: btrahan, scp, chad
Reviewed By: chad
Subscribers: aklapper, qgil, epriestley
Maniphest Tasks: T4843
Differential Revision: https://secure.phabricator.com/D8830
2014-05-01 07:18:18 -07:00
|
|
|
->setAural(pht('Log In'))
|
2014-01-28 20:18:01 -08:00
|
|
|
->setOrder(900);
|
2013-11-13 11:24:38 -08:00
|
|
|
$items[] = $item;
|
|
|
|
}
|
2012-08-05 14:12:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return $items;
|
|
|
|
}
|
|
|
|
|
2013-06-20 11:18:11 -07:00
|
|
|
public function getApplicationGroup() {
|
|
|
|
return self::GROUP_ADMIN;
|
2013-06-17 10:50:43 -07:00
|
|
|
}
|
|
|
|
|
New Registration Workflow
Summary:
Currently, registration and authentication are pretty messy. Two concrete problems:
- The `PhabricatorLDAPRegistrationController` and `PhabricatorOAuthDefaultRegistrationController` controllers are giant copy/pastes of one another. This is really bad.
- We can't practically implement OpenID because we can't reissue the authentication request.
Additionally, the OAuth registration controller can be replaced wholesale by config, which is a huge API surface area and a giant mess.
Broadly, the problem right now is that registration does too much: we hand it some set of indirect credentials (like OAuth tokens) and expect it to take those the entire way to a registered user. Instead, break registration into smaller steps:
- User authenticates with remote service.
- Phabricator pulls information (remote account ID, username, email, real name, profile picture, etc) from the remote service and saves it as `PhabricatorUserCredentials`.
- Phabricator hands the `PhabricatorUserCredentials` to the registration form, which is agnostic about where they originate from: it can process LDAP credentials, OAuth credentials, plain old email credentials, HTTP basic auth credentials, etc.
This doesn't do anything yet -- there is no way to create credentials objects (and no storage patch), but I wanted to get any initial feedback, especially about the event call for T2394. In particular, I think the implementation would look something like this:
$profile = $event->getValue('profile')
$username = $profile->getDefaultUsername();
$is_employee = is_this_a_facebook_employee($username);
if (!$is_employee) {
throw new Exception("You are not employed at Facebook.");
}
$fbid = get_fbid_for_facebook_username($username);
$profile->setDefaultEmail($fbid);
$profile->setCanEditUsername(false);
$profile->setCanEditEmail(false);
$profile->setCanEditRealName(false);
$profile->setShouldVerifyEmail(true);
Seem reasonable?
Test Plan: N/A yet, probably fatals.
Reviewers: vrana, btrahan, codeblock, chad
Reviewed By: btrahan
CC: aran, asherkin, nh, wez
Maniphest Tasks: T1536, T2394
Differential Revision: https://secure.phabricator.com/D4647
2013-06-16 10:13:49 -07:00
|
|
|
public function getRoutes() {
|
|
|
|
return array(
|
|
|
|
'/auth/' => array(
|
2013-06-19 15:00:37 -07:00
|
|
|
'' => 'PhabricatorAuthListController',
|
2013-06-17 10:52:38 -07:00
|
|
|
'config/' => array(
|
|
|
|
'new/' => 'PhabricatorAuthNewController',
|
|
|
|
'new/(?P<className>[^/]+)/' => 'PhabricatorAuthEditController',
|
|
|
|
'edit/(?P<id>\d+)/' => 'PhabricatorAuthEditController',
|
2013-06-17 10:54:08 -07:00
|
|
|
'(?P<action>enable|disable)/(?P<id>\d+)/' =>
|
|
|
|
'PhabricatorAuthDisableController',
|
2013-06-17 10:52:38 -07:00
|
|
|
),
|
2014-02-23 16:39:24 -08:00
|
|
|
'login/(?P<pkey>[^/]+)/(?:(?P<extra>[^/]+)/)?' =>
|
|
|
|
'PhabricatorAuthLoginController',
|
Add password authentication and registration to new registration
Summary:
Ref T1536. Ref T1930. Code is not reachable.
This provides password authentication and registration on the new provider/adapter framework.
I sort of cheated a little bit and don't really route any password logic through the adapter (instead, this provider uses an empty adapter and just sets the type/domain on it). I think the right way to do this //conceptually// is to treat username/passwords as an external black box which the adapter communicates with. However, this creates a lot of practical implementation and UX problems:
- There would basically be two steps -- in the first one, you interact with the "password black box", which behaves like an OAuth provider. This produces some ExternalAccount associated with the username/password pair, then we go into normal registration.
- In normal registration, we'd proceed normally.
This means:
- The registration flow would be split into two parts, one where you select a username/password (interacting with the black box) and one where you actually register (interacting with the generic flow). This is unusual and probably confusing for users.
- We would need to do a lot of re-hashing of passwords, since passwords currently depend on the username and user PHID, which won't exist yet during registration or the "black box" phase. This is a big mess I don't want to deal with.
- We hit a weird condition where two users complete step 1 with the same username but don't complete step 2 yet. The box knows about two different copies of the username, with two different passwords. When we arrive at step 2 the second time we have a lot of bad choices about how to reoslve it, most of which create security problems. The most stragihtforward and "pure" way to resolve the issues is to put password-auth usernames in a separate space, but this would be incredibly confusuing to users (your login name might not be the same as your username, which is bizarre).
- If we change this, we need to update all the other password-related code, which I don't want to bother with (at least for now).
Instead, let registration know about a "default" registration controller (which is always password, if enabled), and let it require a password. This gives us a much simpler (albeit slightly less pure) implementation:
- All the fields are on one form.
- Password adapter is just a shell.
- Password provider does the heavy lifting.
We might make this more pure at some point, but I'm generally pretty satisfied with this.
This doesn't implement the brute-force CAPTCHA protection, that will be coming soon.
Test Plan: Registered with password only and logged in with a password. Hit various error conditions.
Reviewers: btrahan
Reviewed By: btrahan
CC: aran, chad
Maniphest Tasks: T1536, T1930
Differential Revision: https://secure.phabricator.com/D6164
2013-06-16 10:15:49 -07:00
|
|
|
'register/(?:(?P<akey>[^/]+)/)?' => 'PhabricatorAuthRegisterController',
|
2013-06-16 10:15:16 -07:00
|
|
|
'start/' => 'PhabricatorAuthStartController',
|
2013-06-16 10:15:33 -07:00
|
|
|
'validate/' => 'PhabricatorAuthValidateController',
|
2014-05-01 10:23:02 -07:00
|
|
|
'finish/' => 'PhabricatorAuthFinishController',
|
2013-06-17 06:12:45 -07:00
|
|
|
'unlink/(?P<pkey>[^/]+)/' => 'PhabricatorAuthUnlinkController',
|
2013-06-24 15:58:27 -07:00
|
|
|
'(?P<action>link|refresh)/(?P<pkey>[^/]+)/'
|
|
|
|
=> 'PhabricatorAuthLinkController',
|
2013-06-17 06:12:45 -07:00
|
|
|
'confirmlink/(?P<akey>[^/]+)/'
|
|
|
|
=> 'PhabricatorAuthConfirmLinkController',
|
2014-03-17 15:02:01 -07:00
|
|
|
'session/terminate/(?P<id>[^/]+)/'
|
|
|
|
=> 'PhabricatorAuthTerminateSessionController',
|
2014-04-27 17:31:11 -07:00
|
|
|
'session/downgrade/'
|
|
|
|
=> 'PhabricatorAuthDowngradeSessionController',
|
New Registration Workflow
Summary:
Currently, registration and authentication are pretty messy. Two concrete problems:
- The `PhabricatorLDAPRegistrationController` and `PhabricatorOAuthDefaultRegistrationController` controllers are giant copy/pastes of one another. This is really bad.
- We can't practically implement OpenID because we can't reissue the authentication request.
Additionally, the OAuth registration controller can be replaced wholesale by config, which is a huge API surface area and a giant mess.
Broadly, the problem right now is that registration does too much: we hand it some set of indirect credentials (like OAuth tokens) and expect it to take those the entire way to a registered user. Instead, break registration into smaller steps:
- User authenticates with remote service.
- Phabricator pulls information (remote account ID, username, email, real name, profile picture, etc) from the remote service and saves it as `PhabricatorUserCredentials`.
- Phabricator hands the `PhabricatorUserCredentials` to the registration form, which is agnostic about where they originate from: it can process LDAP credentials, OAuth credentials, plain old email credentials, HTTP basic auth credentials, etc.
This doesn't do anything yet -- there is no way to create credentials objects (and no storage patch), but I wanted to get any initial feedback, especially about the event call for T2394. In particular, I think the implementation would look something like this:
$profile = $event->getValue('profile')
$username = $profile->getDefaultUsername();
$is_employee = is_this_a_facebook_employee($username);
if (!$is_employee) {
throw new Exception("You are not employed at Facebook.");
}
$fbid = get_fbid_for_facebook_username($username);
$profile->setDefaultEmail($fbid);
$profile->setCanEditUsername(false);
$profile->setCanEditEmail(false);
$profile->setCanEditRealName(false);
$profile->setShouldVerifyEmail(true);
Seem reasonable?
Test Plan: N/A yet, probably fatals.
Reviewers: vrana, btrahan, codeblock, chad
Reviewed By: btrahan
CC: aran, asherkin, nh, wez
Maniphest Tasks: T1536, T2394
Differential Revision: https://secure.phabricator.com/D4647
2013-06-16 10:13:49 -07:00
|
|
|
),
|
2013-06-16 10:18:45 -07:00
|
|
|
|
2013-06-21 06:11:57 -07:00
|
|
|
'/oauth/(?P<provider>\w+)/login/'
|
|
|
|
=> 'PhabricatorAuthOldOAuthRedirectController',
|
2013-06-19 01:33:27 -07:00
|
|
|
|
2013-06-16 10:18:45 -07:00
|
|
|
'/login/' => array(
|
2013-06-19 01:33:27 -07:00
|
|
|
'' => 'PhabricatorAuthStartController',
|
2013-06-16 10:18:45 -07:00
|
|
|
'email/' => 'PhabricatorEmailLoginController',
|
|
|
|
'etoken/(?P<token>\w+)/' => 'PhabricatorEmailTokenController',
|
|
|
|
'refresh/' => 'PhabricatorRefreshCSRFController',
|
|
|
|
'mustverify/' => 'PhabricatorMustVerifyEmailController',
|
|
|
|
),
|
|
|
|
|
2013-07-10 18:53:09 -07:00
|
|
|
'/emailverify/(?P<code>[^/]+)/' =>
|
|
|
|
'PhabricatorEmailVerificationController',
|
|
|
|
|
2013-06-16 10:18:45 -07:00
|
|
|
'/logout/' => 'PhabricatorLogoutController',
|
New Registration Workflow
Summary:
Currently, registration and authentication are pretty messy. Two concrete problems:
- The `PhabricatorLDAPRegistrationController` and `PhabricatorOAuthDefaultRegistrationController` controllers are giant copy/pastes of one another. This is really bad.
- We can't practically implement OpenID because we can't reissue the authentication request.
Additionally, the OAuth registration controller can be replaced wholesale by config, which is a huge API surface area and a giant mess.
Broadly, the problem right now is that registration does too much: we hand it some set of indirect credentials (like OAuth tokens) and expect it to take those the entire way to a registered user. Instead, break registration into smaller steps:
- User authenticates with remote service.
- Phabricator pulls information (remote account ID, username, email, real name, profile picture, etc) from the remote service and saves it as `PhabricatorUserCredentials`.
- Phabricator hands the `PhabricatorUserCredentials` to the registration form, which is agnostic about where they originate from: it can process LDAP credentials, OAuth credentials, plain old email credentials, HTTP basic auth credentials, etc.
This doesn't do anything yet -- there is no way to create credentials objects (and no storage patch), but I wanted to get any initial feedback, especially about the event call for T2394. In particular, I think the implementation would look something like this:
$profile = $event->getValue('profile')
$username = $profile->getDefaultUsername();
$is_employee = is_this_a_facebook_employee($username);
if (!$is_employee) {
throw new Exception("You are not employed at Facebook.");
}
$fbid = get_fbid_for_facebook_username($username);
$profile->setDefaultEmail($fbid);
$profile->setCanEditUsername(false);
$profile->setCanEditEmail(false);
$profile->setCanEditRealName(false);
$profile->setShouldVerifyEmail(true);
Seem reasonable?
Test Plan: N/A yet, probably fatals.
Reviewers: vrana, btrahan, codeblock, chad
Reviewed By: btrahan
CC: aran, asherkin, nh, wez
Maniphest Tasks: T1536, T2394
Differential Revision: https://secure.phabricator.com/D4647
2013-06-16 10:13:49 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2012-08-05 14:12:43 -07:00
|
|
|
}
|