Skip to content
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

Open
wants to merge 21 commits into
base: master
Choose a base branch
from

Conversation

V1pr
Copy link

@V1pr V1pr commented Apr 15, 2018

  • Added authenticator page support (changes the form destination in login_password_page to plugin page)
  • added autoprovisioning support for CredentialsPage
  • 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

Copy link
Member

@vboctor vboctor left a 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?

.gitignore Outdated Show resolved Hide resolved
core/authentication_api.php Outdated Show resolved Hide resolved
core/authentication_api.php Outdated Show resolved Hide resolved
core/authentication_api.php Outdated Show resolved Hide resolved
* @see $logout_page
* @var string|null
*/
private $authenticator_page = null;
Copy link
Member

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.

Copy link
Author

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.

core/classes/AuthFlags.class.php Outdated Show resolved Hide resolved
$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 ) {
Copy link
Member

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.

Copy link
Author

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
Copy link
Member

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.

Copy link
Author

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

user_ensure_email_unique( $p_email );
email_ensure_valid( $p_email );
email_ensure_not_disposable( $p_email );
if ( ! is_blank($p_email) ) {
Copy link
Member

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.

Copy link
Author

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.

* @param string $p_username The username
* @return string The authenticator page with query string.
*/
function auth_authenticator_page( $p_user_id = null, $p_username = '' ) {
Copy link
Member

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.

Copy link
Author

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)

@vboctor vboctor self-assigned this Apr 15, 2018
added phpdoc to auth_generate_random_password()
…ful install. Newly added .htaccess will handle the rest."

This reverts commit 1c6cfc6.

install.done is not the best idea, since not everyone uses Apache
This reverts commit 7faf9bb.

Using install.done is not the best idea
@V1pr V1pr changed the title Authenticator support with autoprovision; admin dir security Authenticator support with autoprovision Apr 17, 2018
@V1pr V1pr changed the title Authenticator support with autoprovision Extend auth plugin support: enable autoprovision and add authenticator page support Apr 17, 2018
@V1pr
Copy link
Author

V1pr commented Apr 17, 2018

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.

@V1pr
Copy link
Author

V1pr commented May 30, 2018

Ping?

@aborderon
Copy link

@vboctor Do you have any elements to communicate to advance this amendment? Because it interests us.
Thank you

@aborderon
Copy link

@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

@V1pr
Copy link
Author

V1pr commented Jun 11, 2018

@aborderon thanks, I've opened a ticket.
@vboctor @dregad is there anything else I need to do speed the merge up a bit?

@dregad
Copy link
Member

dregad commented Jun 12, 2018

With the revert of the .gitignore change, I don't have any issues with your PR. I let you follow up with vboctor.

/**
* Gets the page that validates the user credentials based on the standard flow.
*
* @param string $p_query_string The query string, can be empty.
Copy link
Member

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

Copy link
Author

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

Copy link
Member

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/authentication_api.php Outdated Show resolved Hide resolved
core/authentication_api.php Outdated Show resolved Hide resolved
/**
* Sets if the auth pugin is capable of provision users
*
* @param bool capability
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$p_autoprov

@@ -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); ?>">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spaces after/before parentheses

* @see setAutoprovisionCapability()
*/
function getAutoprovisionCapability() {
if( is_null( $this->autoprovision_capability ) ) {
Copy link
Member

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

return false;
}

return $this->autoprovision_capability;
Copy link
Member

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

user_ensure_email_unique( $p_email );
email_ensure_valid( $p_email );
email_ensure_not_disposable( $p_email );
if( !is_blank( $p_email ) ) {
Copy link
Member

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)

Copy link
Author

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,

Copy link
Author

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.

core/user_api.php Outdated Show resolved Hide resolved
@aborderon
Copy link

@V1pr news ?

@V1pr
Copy link
Author

V1pr commented Aug 31, 2018

@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?

@V1pr
Copy link
Author

V1pr commented Oct 1, 2018

@dregad @vboctor @atrol ping?

@atrol
Copy link
Member

atrol commented Oct 1, 2018

I am a bit concerned, as this is security related authentication code and it seems that this code has not been tested that much.
e.g. getAutoprovisionCapability did not work due to access to non-existing autoprovision_capability before V1pr addressed my comments in b036694

When I reviewed in June, I didn't test anything, just did some static code review.
I don't use auth plugin functionality myself and I am not able to invest time in having a deeper look and tests.

Sorry @V1pr, I will not be the one who approves the PR.

Copy link
Member

@dregad dregad left a 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.

@V1pr
Copy link
Author

V1pr commented Oct 1, 2018

Thank you Gents! I'll wait for @vboctor 's approval/comments.

Copy link
Member

@vboctor vboctor left a 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:

  1. EVENT_AUTH_VERIFY_PASSWORD (taking username / password) - this is used to validate user password instead of the MantisBT database.
  2. 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:

  1. Simple - Use standard flow but inject external password validation and possibly auto-provisioning.
  2. 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.

core/authentication_api.php Show resolved Hide resolved
core/classes/AuthFlags.class.php Show resolved Hide resolved
login_password_page.php Show resolved Hide resolved
core/classes/AuthFlags.class.php Show resolved Hide resolved
@vboctor
Copy link
Member

vboctor commented Oct 3, 2018

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

@V1pr
Copy link
Author

V1pr commented May 25, 2020

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.

@vboctor vboctor added the plugins Pull requests related to plugins and events label Apr 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
plugins Pull requests related to plugins and events
Projects
None yet
5 participants