New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extend auth plugin support: enable autoprovision and add authenticator page support #1333
base: master
Are you sure you want to change the base?
Conversation
…all. Newly added .htaccess will handle the rest.
- If autoprovision is supported by the plugin, than redirection is allowed to credentials page (if set by plugin)
no-fast-forward
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @V1pr for your contribution.
- I have added few comments in the code that would need addressing.
- Please create issue(s) in the bug tracker and reference them from the pull request.
- Would be good to explain in the PR / issues some of the flows that would be possible because of the changes in this PR. Screenshots would be a plus if you have them.
- If you have a gist or similar with sample code, then reference them from PR. I noticed you had a PR for SampleAuth, but I didn't check it out yet.
- Do we have the right hooks for an authenticator plugin to plugin the setup of the authenticator app?
* @see $logout_page | ||
* @var string|null | ||
*/ | ||
private $authenticator_page = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason why this shouldn't be transparent from core and implemented as part of $credentials_page
and potentially other pages related to it as per plugin implementation? For example, you can imagine the credentials page asking for password, then redirecting to authenticator, then logging in the user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is separate by intention. In the updated readme of SampleAuth I described it in detail. Main reason is, that $credentials_page
is mainly for SSO IMHO (with separate password request page), while $authenticator_page
replaced the standard login.php for access validation - but uses the Mantis username/password aquisition pages.
login_password_page.php
Outdated
$t_user_id = auth_get_user_id_from_login_name( $t_username ); | ||
if( $t_user_id !== false && auth_credential_page( '', $t_user_id ) != AUTH_PAGE_CREDENTIAL ) { | ||
if( ( $t_user_id !== false || authenticator_autoprov_capable() ) && auth_credential_page( '', $t_user_id ) != AUTH_PAGE_CREDENTIAL ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we have a logic like the following before this block:
if( $t_user_id === false ) {
$t_user_id = auth_provision_user( $p_username );
}
// then use the existing logic
In this case, we always give plugins the change to provision the user, but they make decide that a username doesn't exist in the identity system and hence it shouldn't be provisioned or they don't support auto-provision. Hence, we replace authenticator_autoprov_capable()
with auth_provision_user( $p_username )
. The auth_provision_user() returns user id created or false.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this will not work with SSO systems. I mean, if you set $credentials_page to support SSO/external password aqusition page, than you'll not get redirected to the plugin page.
# | ||
# OR | ||
# | ||
# if the plugin provides autoprovisioning, than we can also redirect to the plugin page |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please explain the expected flow(s) when user is not found. Explain the case where use should be provisioned and the other where user wouldn't be provisioned because it doesn't exist in identity system.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my opinion, user provisioning must always run afterwards authentication. If I use a plugin for auth and the user not yet exists in the system, than I want to do provisioning only, if the user authenticated himself correctly (that's why I set the flag for autoprov capable)
The flow:
- if user found -> go to plugin page and to the auth
- if user not found:
- if plugin can do autoprov, than continue to auth
- if pluging cannot do autoprov, than skip plugin auth and use standard flow
core/user_api.php
Outdated
user_ensure_email_unique( $p_email ); | ||
email_ensure_valid( $p_email ); | ||
email_ensure_not_disposable( $p_email ); | ||
if ( ! is_blank($p_email) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Proper formatting is if( !is_blank( $p_email ) ) {
. But why do we need this check? The existing methods should apply the right validation based on configuration like whether or not to allow empty email addresses via $g_allow_blank_email
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added this to make the autoprov work. I've failed to notice the $g_allow_blank_email in the code, but there can be scenarios, when it's not possible to turn it on (=allowing blank e-mails); like if signup is enabled, but I want to use external auth besides it with autoprov.
My initial problem was, than if I supply an e-mail to user_create, than a signup e-mail will be sent to the user, which I want to avoid. I would also be possible to add a new parameter to the function, like 'p_dont_send_signup_email', but I did not want to do that not knowing your future ideas with user_create.
core/authentication_api.php
Outdated
* @param string $p_username The username | ||
* @return string The authenticator page with query string. | ||
*/ | ||
function auth_authenticator_page( $p_user_id = null, $p_username = '' ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The term authenticator
reflects a specific implementation. We should probably consider extended_auth
. It can work with all kinds of 2FA or any other approach (e.g. security questions), etc.
I would expect such page to be visible only after user enters their correct credentials via the standard password page. If user is using a custom credentials page, then this setting wouldn't be applicable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The user is either using credentials_page OR authenticator_page. The former request the password from the user and authenticates it (or does SSO), while the later replaces the standard login.php and handles the authentication (redirects to login.php if unsuccessful).
Reasoning: I wanted to use the standard mantis flow (username and password aquisition), but was not able to change login.php to support the plugin as a second auth mech, since the authflags got resetted to default before the redirect and changing this seemed to be a much deeper change. I named is authenticator
, because the page actually does the authentication with the username/password POST-ed to it (see SampleAuth readme in PR)
I can't seem to find the place, where I can create an issue#/feture req.#. What am I missing? About your last question: this setup works with my extended version on SampleAuth plugin (also added a lot of comments to it, with a more detailed readme). However, I found that the auth plugin concept might needs some work. I would change it to a "stack like" method. A plugin registers itself to the core with a set of flags (including priority of the mech). Upon login the core checks the corresponding plugins in priority order taking the flag into consideration when checking. |
Ping? |
@vboctor Do you have any elements to communicate to advance this amendment? Because it interests us. |
@V1pr about creating problems in the bug tracker and referencing them from the pull request. You have to go here : https://www.mantisbt.org/bugs/view_all_bug_page.php |
@aborderon thanks, I've opened a ticket. |
With the revert of the .gitignore change, I don't have any issues with your PR. I let you follow up with vboctor. |
core/authentication_api.php
Outdated
/** | ||
* Gets the page that validates the user credentials based on the standard flow. | ||
* | ||
* @param string $p_query_string The query string, can be empty. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
parameter $p_query_string does not exist
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, I don't get this one. $p_query_string exists as an input parameter for auth_credential_page
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this the PHPdoc for auth_authenticator_page ?
core/classes/AuthFlags.class.php
Outdated
/** | ||
* Sets if the auth pugin is capable of provision users | ||
* | ||
* @param bool capability |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$p_autoprov
login_password_page.php
Outdated
@@ -201,7 +206,7 @@ | |||
<?php echo $t_form_title ?> | |||
</h4> | |||
<div class="space-10"></div> | |||
<form id="login-form" method="post" action="login.php"> | |||
<form id="login-form" method="post" action="<?php echo auth_authenticator_page($t_user_id, $t_username); ?>"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
spaces after/before parentheses
core/classes/AuthFlags.class.php
Outdated
* @see setAutoprovisionCapability() | ||
*/ | ||
function getAutoprovisionCapability() { | ||
if( is_null( $this->autoprovision_capability ) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/autoprovision_capability/autoprovision_capable
core/classes/AuthFlags.class.php
Outdated
return false; | ||
} | ||
|
||
return $this->autoprovision_capability; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/autoprovision_capability/autoprovision_capable
core/user_api.php
Outdated
user_ensure_email_unique( $p_email ); | ||
email_ensure_valid( $p_email ); | ||
email_ensure_not_disposable( $p_email ); | ||
if( !is_blank( $p_email ) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did you introduce this check?
After your change, blank email addresses can be set even if $g_allow_blank_email = OFF; (our default setting)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I remember correctly, I ran into issues upon automatic user creation, but I must have overlooked something. I'll revert this one and add a comment to SampleAuth,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've found the answer in SampleAuth: the reason was behind this, that Mantis will send a SignUP e-mail, if e-mail is provided (which I did not want), so I create the use with empty e-mail and assign the email afterwards. See SampleAuth plugin. Anyway, I'll change the logic/doc in SampleAuth.
This reverts commit fea867a. Conflicts: core/user_api.php
@V1pr news ? |
@aborderon none, that I know of :( I did what I can :( @dregad @vboctor @atrol is there anything I can do, to speed the things up? |
I am a bit concerned, as this is security related authentication code and it seems that this code has not been tested that much. When I reviewed in June, I didn't test anything, just did some static code review. Sorry @V1pr, I will not be the one who approves the PR. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned in #1333 (comment), I'm fine with the PR as it stands. But since @vboctor had some remarks initially (which you seem to have addressed), I'd like to have his feedback before merging it.
Thank you Gents! I'll wait for @vboctor 's approval/comments. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have added few comments based on current approach.
I think with the possible ways to override the auth flow it is getting a bit too complicated. I wonder if we can simplify by having the standard flow inject the following events:
- EVENT_AUTH_VERIFY_PASSWORD (taking username / password) - this is used to validate user password instead of the MantisBT database.
- EVENT_AUTH_PROVISION_USER (taking username - plugin can implement by fetching user info and creating a MantisBT user or just do nothing)
In this case case, there would be two approaches for auth plugins:
- Simple - Use standard flow but inject external password validation and possibly auto-provisioning.
- Advanced - Take over credential page and implement a completely custom credential - e.g. password + 2FA.
This would remove the use of authenticator page, the auto-provision auth flag, etc.
We can even have a single plugin event to verify password and provision if necessary. The event can take the username and password and return false in case of failure or user id (matched or provisioned). EVENT_AUTH_VERIFY_PASSWORD_AND_PROVISION You can imagine multiple auth plugins subscribed to this event and the first one that succeeds would win. Thanks @V1pr |
In this case, you'll likely have an userid collision soon. Using multiple auth backends in a frontend application is imho never a good idea. Authenticator backends should be handled by the authenticator app (SSO or something like that), not an application. |
added automatic admin directory security with .htaccess if a specific file (install.done) exists. This is created upon a successful install(removed/reverted)https://www.mantisbt.org/bugs/view.php?id=24535