Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions README.md

This file was deleted.

97 changes: 97 additions & 0 deletions SimpleSAMLphpAuth.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php
# Licensed under the MIT license

/**
* Sample Auth plugin
*/
class SimpleSAMLphpAuthPlugin extends MantisPlugin {
/**
* A method that populates the plugin information and minimum requirements.
* @return void
*/
function register() {
$this->name = plugin_lang_get( 'title' );
$this->description = plugin_lang_get( 'description' );
$this->page = 'config_page';

$this->version = '0.1';
$this->requires = array(
'MantisCore' => '2.4.0',
);

$this->author = 'Erwann PENET';
$this->contact = '';
$this->url = 'https://github.com/mantisbt-plugins/SimpleSAMLphpAuth';
}

/**
* plugin hooks
* @return array
*/
function hooks() {
$t_hooks = array(
'EVENT_AUTH_USER_FLAGS' => 'auth_user_flags',
);

return $t_hooks;
}

function config() {
return array(
Copy link
Member

Choose a reason for hiding this comment

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

How about adding a test_users that can be set to a comma separated usernames to only enable the plugin for such users for testing. If not set/empty, then plugin applies to all. That enables the admin to test on a specific accounts before playing around with configs which may lock everybody out.

'autoloader_path' => '',
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need a file path in the configs? Why can't this path be known by the plugin assuming the library is bundled with the plugin? Even if for some reason we think this is needed, I wouldn't surface it in the UI and keep it as an internal config option that can be overridden in config/config_inc.php. But ideally, I would try to get rid of this config.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is linked to the workings of SimpleSAMLphp.
It is a standalone installation, separate from the core Mantis installation.

'SP_name' => '',
Copy link
Member

Choose a reason for hiding this comment

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

How about service_provider as the config option name?

'auth_attributes_username' => '',
'auth_attributes_email' => ''
);
}

function auth_user_flags( $p_event_name, $p_args ) {
# Don't access DB if db_is_connected() is false.

$t_username = $p_args['username'];

$t_user_id = $p_args['user_id'];

# If user is unknown, don't handle authentication for it, since this plugin doesn't do
# auto-provisioning
if( !$t_user_id ) {
return null;
}

# If anonymous user, don't handle it.
if( user_is_anonymous( $t_user_id ) ) {
return null;
}

$t_access_level = user_get_access_level( $t_user_id, ALL_PROJECTS );

/*
# Have administrators use default login flow
if( $t_access_level >= ADMINISTRATOR ) {
return null;
}
*/

# for everybody else use the custom authentication
$t_flags = new AuthFlags();

# Passwords managed externally for all users
$t_flags->setCanUseStandardLogin( false );
$t_flags->setPasswordManagedExternallyMessage( 'Passwords are no more, you cannot change them!' );
Copy link
Member

Choose a reason for hiding this comment

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

This message should be localized via a language file.


# No one can use standard auth mechanism

# Override Login page and Logout Redirect
$t_flags->setCredentialsPage( helper_url_combine( plugin_page( 'login', /* redirect */ true ), 'username=' . $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.

You should url encode the username.

$t_flags->setLogoutRedirectPage( plugin_page( 'logout', /* redirect */ true ) );

# No long term session for identity provider to be able to kick users out.
$t_flags->setPermSessionEnabled( false );

# Enable re-authentication and use more aggressive timeout.
$t_flags->setReauthenticationEnabled( true );
$t_flags->setReauthenticationLifetime( 10 );
Copy link
Member

Choose a reason for hiding this comment

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

The default 5 minutes seems reasonable. 10 seconds seems to be an overkill even if the overhead is just a redirect to an IDP and back. I suggest leaving this to default in MantisBT or having it as a config for the plugin.


return $t_flags;
}
}
14 changes: 14 additions & 0 deletions lang/strings_english.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php
# Copyright (c) MantisBT Team - [email protected]
# Licensed under the MIT license

$s_plugin_SimpleSAMLphpAuth_title = 'AuthSimpleSAMLphp';
Copy link
Member

Choose a reason for hiding this comment

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

This name is not consistent with the plugin name. I also think it would make more sense to use a more user friendly name here. For example, SAML Auth or SAML Auth via SimpleSAMLAuth.

$s_plugin_SimpleSAMLphpAuth_description = 'A plugin for authentication using SimpleSAMLphp: https://simplesamlphp.org.';

$s_plugin_SimpleSAMLphpAuth_update = 'Update';

$s_plugin_SimpleSAMLphpAuth_configuration = 'Configuration';
$s_plugin_SimpleSAMLphpAuth_config_autoloader_path = 'SimpleSAMLphp autoloader path';
$s_plugin_SimpleSAMLphpAuth_config_SP_name = 'SimpleSAMLphp SP name';
Copy link
Member

Choose a reason for hiding this comment

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

"config_" isn't really necessary. No need for "SimpleSAMLphp" in the UI string. Also I would use "Service Provider Name" instead of "SP name".

$s_plugin_SimpleSAMLphpAuth_config_auth_attributes_username = 'Username attribute';
$s_plugin_SimpleSAMLphpAuth_config_auth_attributes_email = 'Email attribute';
58 changes: 58 additions & 0 deletions pages/config_page.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php
# Licensed under the MIT license
access_ensure_global_level( ADMINISTRATOR );
auth_reauthenticate();

layout_page_header( plugin_lang_get( 'title' ) . ': ' . plugin_lang_get( 'configuration' ) );
layout_page_begin( 'manage_overview_page.php' );
print_manage_menu( 'manage_plugin_page.php' );
?>

<div class="col-md-12 col-xs-12">
<div class="space-10"></div>
<div class="form-container">
<form action="<?php echo plugin_page( 'config_update' ) ?>" method="post">
<fieldset>
<div class="widget-box widget-color-blue2">
<div class="widget-header widget-header-small">
<h4 class="widget-title lighter">
<i class="ace-icon fa fa-exchange"></i>
<?php echo plugin_lang_get( 'title' ), ': ', plugin_lang_get( 'configuration' ) ?>
</h4>
</div>
<?php echo form_security_field( 'plugin_SimpleSAMLphpAuth_config_update' ) ?>
<div class="widget-body">
<div class="widget-main no-padding">
<div class="table-responsive">
<table class="table table-bordered table-condensed table-striped">
<tr>
<td class="category"><?php echo plugin_lang_get( 'config_autoloader_path' ) ?></td>
<td><input type="text" name="autoloader_path" value="<?php echo plugin_config_get( 'autoloader_path' ) ?>"/></td>
</tr>
<tr>
<td class="category"><?php echo plugin_lang_get( 'config_SP_name' ) ?></td>
<td><input type="text" name="SP_name" value="<?php echo plugin_config_get( 'SP_name' ) ?>"/></td>
</tr>
<tr>
<td class="category"><?php echo plugin_lang_get( 'config_auth_attributes_username' ) ?></td>
<td><input type="text" name="auth_attributes_username" value="<?php echo plugin_config_get( 'auth_attributes_username' ) ?>"/></td>
</tr>
<tr>
<td class="category"><?php echo plugin_lang_get( 'config_auth_attributes_email' ) ?></td>
<td><input type="text" name="auth_attributes_email" value="<?php echo plugin_config_get( 'auth_attributes_email' ) ?>"/></td>
</tr>
</table>
</div>
</div>
<div class="widget-toolbox padding-8 clearfix">
<input type="submit" class="btn btn-primary btn-white btn-round" value="<?php echo plugin_lang_get( 'update' ) ?>" />
</div>
</div>
</div>
</fieldset>
</form>
</div>
</div>

<?php
layout_page_end();
21 changes: 21 additions & 0 deletions pages/config_update.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php
# Licensed under the MIT license

form_security_validate( 'plugin_SimpleSAMLphpAuth_config_update' );

access_ensure_global_level( ADMINISTRATOR );
auth_reauthenticate();

function maybe_set_option( $name, $value ) {
if ( $value != plugin_config_get( $name ) ) {
plugin_config_set( $name, $value );
}
}

maybe_set_option( 'autoloader_path', gpc_get_string( 'autoloader_path' ) );
maybe_set_option( 'SP_name', gpc_get_string( 'SP_name' ) );
maybe_set_option( 'auth_attributes_username', gpc_get_string( 'auth_attributes_username' ) );
maybe_set_option( 'auth_attributes_email', gpc_get_string( 'auth_attributes_email' ) );

form_security_purge( 'plugin_SimpleSAMLphpAuth_config_update' );
print_successful_redirect( plugin_page( 'config_page', true ) );
54 changes: 54 additions & 0 deletions pages/login.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php
# Licensed under the MIT license

require_once( 'core.php' );
require_api( 'authentication_api.php' );
require_api( 'user_api.php' );

$f_username = gpc_get_string( 'username' );
$f_reauthenticate = gpc_get_bool( 'reauthenticate', false );
$f_return = gpc_get_string( 'return', config_get( 'default_home_page' ) );

$t_return = string_url( string_sanitize_url( $f_return ) );

require_once( plugin_config_get( 'autoloader_path' ) );
$t_simplesamlphp_instance = new SimpleSAML_Auth_Simple( plugin_config_get( 'SP_name' ) );
$t_simplesamlphp_instance->requireAuth();
if( $t_simplesamlphp_instance->isAuthenticated() ) {
$t_simplesamlphp_attributes = $t_simplesamlphp_instance->getAttributes();
Copy link
Member

Choose a reason for hiding this comment

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

indentation seems to be inconsistent.

$f_username = $t_simplesamlphp_attributes[ plugin_config_get( 'auth_attributes_username' ) ][0];
Copy link
Member

Choose a reason for hiding this comment

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

Check that the attribute is set before retrieving it to avoid php errors in case plugin is misconfigured during testing.

}

$t_user_id = is_blank( $f_username ) ? false : user_get_id_by_name( $f_username );

if( $t_user_id == false ) {
$t_query_args = array(
'error' => 1,
'username' => $f_username,
);

if( !is_blank( 'return' ) ) {
$t_query_args['return'] = $t_return;
}

if( $f_reauthenticate ) {
$t_query_args['reauthenticate'] = 1;
}

$t_query_text = http_build_query( $t_query_args, '', '&' );

$t_uri = auth_login_page( $t_query_text );

print_header_redirect( $t_uri );
}

# Let user into MantisBT
auth_login_user( $t_user_id );

# Redirect to original page user wanted to access before authentication
if( !is_blank( $t_return ) ) {
print_header_redirect( 'login_cookie_test.php?return=' . $t_return );
}

# If no return page, redirect to default page
print_header_redirect( config_get( 'default_home_page' ) );
13 changes: 13 additions & 0 deletions pages/logout.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php
# Licensed under the MIT license
require_once( 'core.php' );
require_api( 'authentication_api.php' );

require_once( plugin_config_get( 'autoloader_path' ) );
$t_simplesamlphp_instance = new SimpleSAML_Auth_Simple( plugin_config_get( 'SP_name' ) );
$t_simplesamlphp_instance->logout(config_get( 'path' ) . auth_login_page());

# User is already logged out from Mantis
# TODO: logout from external identity provider

print_header_redirect( auth_login_page(), true, false );
22 changes: 22 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# SimpleSAMLphpAuth Plugin

This is an authentication plugin for SimpleSAMLphp.

The authentication mechanism implemented by this plugin works as follows:
- If users_no_saml config setting is not empty, and contains the user ID, use standard authentication.
- If users_saml config setting is not empty, and **doesn't** contain user ID, use standard authentication.
- If user is not registered in the db, user standard behavior.
- Otherwise, auto-signin the user without a password.

Users that are auto-signed in, can't manage or use passwords that are stored in the MantisBT database.

## Configuration options
- **autoloader_path** this is the path to the autoloader for simplesaml (eg. /simplesaml/lib/_autoload.php)
- **service_provider** this is the name of the service provider for simplesaml (eg. default-sp)
- **auth_attributes_username** this is the name of the SAML attribute containing the username of the user (used for matching user account)
- **auth_attributes_email** this is the name of the SAML attribute containing the email of the user (used for user provisionning)
- **users_no_saml** users (one username per line) to bypass SAML authentication (eg. administrators)
- **users_saml** users (one username per line) for which to use SAML authentication (eg. for testing before deploying to all users)

## Dependencies
MantisBT v2.4.0