Change the /user/login path?

We encourage users to post events happening in the community to the community events group on https://www.drupal.org.
Matthew Krick's picture

I'm currently working on a site for a client who's a bit overly paranoid. When he learned that all drupal sites have a login page at /user/login he asked me to change that path to something else so he "won't get hacked".

I can't seem to figure out how to do it! Anyone have an idea? I've checked site info and other parts of the admin menu, my settings.php, no luck.

Comments

Hi Matthew, One way to do

tom friedhof's picture

Hi Matthew,

One way to do this is to write a module. You'll have to override the menu path for the user/login path and set it as access denied using hook_menu_alter(). Then you'll need to define a hook_menu() to define a new menu path to your secret login page.

For fun, I wrote a small module to do this for you. Just create the .info file and it should be ready to install. This module will give you a login screen at the path: /supersecretloginplace.

Let me know how it works, or if you find a different way to handle this.

/**
 * Implementation of hook_menu.
 * Create our new path to the new login screen.
 */
function moveloginpage_menu() {
  $items = array();

  $items['supersecretloginplace'] = array(
    'title' => 'Super Secret Login Page',
    'page callback' => 'moveloginpage_user_page',
    'page arguments' => array(true),
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );

  return $items;
}

/**
 * Implementation of hook_menu_alter.
 * Tell the menu system to use our custom callback rather than the core callback.
 */
function moveloginpage_menu_alter(&$items) {
  $items['user']['page callback'] = 'moveloginpage_user_page';
}

/**
 * Access callback for path /user.
 *
 * Displays user profile if user is logged in, or login form for anonymous
 * users if using our special path, access denied if using default path.
 */
function moveloginpage_user_page($show = false) {
  global $user;
  if ($user->uid) {
    menu_set_active_item('user/'. $user->uid);
    return menu_execute_active_handler();
  }
  else if ($show) {
    return drupal_get_form('user_login');
  }
  
  drupal_access_denied();
}

/user to throw a 404 instead of access denied?

jkatinger's picture

Tom - this is awesome and works perfectly for me. Thanks! However, what if, when this module is active, I wanted anyone who goes to /user to get a 404 page instead of access denied? So it looked like the whole admin/login system didn't exist? Of course, if you were logged in, then /user should work as normal. Any thoughts?

All you would have to to is

tom friedhof's picture

All you would have to to is replace drupal_access_denied() function call at the end of the module with a drupal_not_found() function call. That would give you the 404 page instead.

Thanks

deoxyna's picture

Hi tom,

works great for me. thanks a lot.

Awsome!!

zeev's picture

It is working for me well.. !! :)

Thanks "tom friedhof" !!

I was seaching for a solution to change the '/user/' page path and this module made it work for my site. :)

Changing the user login path

ecosnow's picture

Hey tom friedhof!

Considering this is an old posting and still no mod to d/l, I can't see the mod to activate in the module list. Using D7.10 and would love to see this mod as a d/l. Peace and many thanks. :)

Thanks Tom, I'll let ya know

Matthew Krick's picture

Thanks Tom,

I'll let ya know how it works out!

Hey Tom, I must be doing

Matthew Krick's picture

Hey Tom,

I must be doing something wrong. I created a secretlogin.info file and copied the code you provided into a secretlogin.module file, placed them both in a folder (named secretlogin) and enabled it, but I just get an error at the top of the screen spitting out the code pasted in the module file.

This is what I put in the Info file.

; $Id$
name = Secret Login
description = "Super Secret Login"
core = 6.x

If you copied the code

tom friedhof's picture

If you copied the code verbatim into a file called secretlogin.module, then you will need to find and replace the function signatures to have secretlogin instead of moveloginpage at the beginning of each function name. For example change:

function moveloginpage_menu()

to

function secretlogin_menu()

The hooks in the module are invoked by calling <modulename>_<hookname>. You'll need to change every function in the module so that each function name starts with the module name.

It's not working for me when

vestris's picture

It's not working for me when site is closed for maintenance (admin/settings/site-maintenance). Path to /supersecretloginplace not available.

Maybe, you can help me with it... -(

Yeah, the user path is

tom friedhof's picture

Yeah, the user path is hardcoded into the menu system. If you really want this to work with your secret URL, you would have to hack the menu.inc file in the includes directory (includes/menu.inc). Look for the the line in the code below that says:
/****** HACK THIS LINE BELOW ******/

function _menu_site_is_offline() {
  // Check if site is set to off-line mode.
  if (variable_get('site_offline', 0)) {
    // Check if the user has administration privileges.
    if (user_access('administer site configuration')) {
      // Ensure that the off-line message is displayed only once [allowing for
      // page redirects], and specifically suppress its display on the site
      // maintenance page.
      if (drupal_get_normal_path($_GET['q']) != 'admin/settings/site-maintenance') {
        drupal_set_message(l(t('Operating in off-line mode.'), 'admin/settings/site-maintenance'), 'status', FALSE);
      }
    }
    else {
      // Anonymous users get a FALSE at the login prompt, TRUE otherwise.
      if (user_is_anonymous()) {
        /****** HACK THIS LINE BELOW ******/
        return $_GET['q'] != 'supersecretloginplace' && $_GET['q'] != 'user/login';
      }
      // Logged in users are unprivileged here, so they are logged out.
      require_once drupal_get_path('module', 'user') .'/user.pages.inc';
      user_logout();
    }
  }
  return FALSE;
}

It is generally frowned upon to hack core, but sometimes you have no choice. In this case you have no other choice but to hack core because the URL is hardcoded in. In this scenario, I would just create a patch file of the hack, so as you upgrade Drupal, you can just reapply the patch to a clean file.

It's ok to hack core when there is no other way, but you need to keep track of your patches against a pristine core.

Core could actually handle this better if the user module actually registered the user login path, so that other modules can overwrite it, like I have done with this pseudo module.

Thank you very much for your

vestris's picture

Thank you very much for your assistance and kind explanations. It was very helpful.

removing registration and password pages as well

novice's picture

Taking the lead from this I was trying to remove the registration and password pages as well but getting nowhere. Here is the code I have so far.
Going to /user/password gets me 'page not found' as expected however going to /sspassword gets me the page but with a warning instead of the form:

"warning: call_user_func_array() [function.call-user-func-array]: First argument is expected to be a valid callback, 'user_pass' was given in /usr/share/users/simha/includes/form.inc on line 366."

/user/register, however, still continues to work. As a matter of fact, i put in a var_dump and i don't see it on the webpage which means it is not even going to the function. And then /ssregister gives a page not found. I have even tried to modify the moveregisterpage_user_page function unconditionally to use drupal_goto() to send to home page but looks like the function is not getting called at all.

BTW, I also installed the 'util' module to assign a weight to the new module so that it gets loaded the last (just in case it was not).

Thanks in advance for your help.

here is the code:

<?php
/**
* Implementation of hook_menu.
* Create our new path to the new login screen.
*/
function moveloginpage_menu() {
  $items = array();

  $items['sslogin'] = array(
    'title' => 'Super Secret Login Page',
    'page callback' => 'moveloginpage_user_page',
    'page arguments' => array(true),
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );

  $items['sspassword'] = array(
    'title' => 'Super Secret Password Page',
    'page callback' => 'movepasswordpage_user_page',
    'page arguments' => array(true),
    'access callback' => 'user_is_anonymous',
    'type' => MENU_LOCAL_TASK,
    'file' => 'user.pages.inc',

  );

  $items['ssregister'] = array(
    'title' => 'Super Secret Registration Page',
    'page callback' => 'moveregisterpage_user_page',
    'page arguments' => array(true),
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );

  return $items;
}


/**
* Implementation of hook_menu_alter.
* Tell the menu system to use our custom callback rather than the core callback.
*/
function moveloginpage_menu_alter(&$items) {
  $items['user']['page callback'] = 'moveloginpage_user_page';
  $items['user/password']['page callback'] = 'movepasswordpage_user_page';
  $items['user/password']['page arguments'] = array(false);
  $items['user/register']['page callback'] = 'moveregisterpage_user_page';
  $items['user/register']['page arguments'] = array(false);
}

/**
* Access callback for path /user.
*
* Displays user profile if user is logged in, or login form for anonymous
* users if using our special path, access denied if using default path.
*/
function moveloginpage_user_page($show = false) {
  global $user;
  if ($user->uid) {
    menu_set_active_item('user/'. $user->uid);
    return menu_execute_active_handler();
  }
  else if ($show) {
    return drupal_get_form('user_login');
  }

  drupal_not_found();
}

function movepasswordpage_user_page($show = false) {
  global $user;
  var_dump($user);
  var_dump($show);
  if ($user->uid) {
    menu_set_active_item('user/password'. $user->uid);
    return menu_execute_active_handler();
  }
  else if ($show === 'user_pass' ) {
    return drupal_not_found();
  }
  retrun drupal_get_form('user_pass');
}

function moveregisterpage_user_page($show = false) {
  global $user;
  var_dump($user);
  var_dump($show);

  if ($user->uid) {
    menu_set_active_item('user/register'. $user->uid);
    return menu_execute_active_handler();
  }
  else if ($show === 'user_register') {
        return drupal_not_found();
  }
  return drupal_get_form('user_register');
}

Did you ever solve it?

tammo's picture

I am looking at the same problem, but have not found a solution so far.

I hope you have found a solution in the meantime....

Greetings from Holland,

Tammo

RE: removing registration and password pages as well

roheim's picture

The problem you are having is that you are trying to call code that is not included yet.

If you look in user.module you will see this on line 1611 or so:

<?php
  $items
['user/password'] = array(
   
'title' => 'Request new password',
   
'page callback' => 'drupal_get_form',
   
'page arguments' => array('user_pass'),
   
'access callback' => TRUE,
   
'type' => MENU_LOCAL_TASK,
   
'file' => 'user.pages.inc',
  );
?>

So you have to load the user.pages.inc file and you are good to go.

Hope it helps.

roheim

David Roheim

An alternate solution

sdea's picture

You could install a version of http://drupal.org/project/noreqnewpass

You could modify noreqnewpass.module by adding 3 lines to noreqnewpass_menu_alter

/**
* Implementation of hook_menu_alter().
*/
function noreqnewpass_menu_alter(&$callback) {
if (variable_get('noreqnewpass_disabled', true)) {
$callback['user/password'] = array('access arguments' => array(FALSE));
$callback['user/register'] = array('access arguments' => array(FALSE));
$callback['user/login'] = array('access arguments' => array(FALSE));
$callback['user'] = array('access arguments' => array(FALSE));
}
}

The three new lines would be:

$callback['user/register'] = array('access arguments' => array(FALSE));
$callback['user/login'] = array('access arguments' => array(FALSE));
$callback['user'] = array('access arguments' => array(FALSE));

noreqnewpass will only hide tab from user page

gennadiy's picture

noreqnewpass will only hide tab from user's page, but if you enter the usual path /user/password the form is still there.

Drupal 7 port ?

patoshi's picture

hi anyone know if there is a module like this for Drupal 7 ? i too would like to change the /user login page as there are alot of bots preying on drupal sites since they all have the same login page on /user

Would really like to have

goldlilys's picture

Would really like to have this module ported for D7, is there no official release for this module yet ?

Uniquely Creative & Simply Efficient Websites. Visit Goldlilys Media.

Working

dirarko's picture

Just what I want, thanks a lot

VortexCentrum's picture

The spamming of Drupal sites and the creation of fraudulent accounts (mainly by bots) is a serious issue. It costs site owners time (and therefore money).

Within 24 hours of opening registration on one of our (20 odd) sites a couple of days ago, we had more than 100 fraudulent accounts.

We stopped them in their tracks by two simple methods: first (and most obviously) captcha (we used the maths version) and by putting a front-page link that said it went to login/registration but in fact went to an intervening page with two links on it - one to a fictitious domain name (and so a dead end) and, later in the page) one to the correct userpage.

But neither of those methods block the bots that know which page to go to. And there are millions of site-owners who, like us, have this problem.

The code above seems to do exactly what we would need (but it's a bit scary from a non-techie's perspective) and I wonder if there might be a way to deal with this at the installation stage.

Would it be possible for the installation package to ask, before installation, for a page name for the page that is currently called "user" ?

I wonder if the easiest way (for those that know what they are doing - which isn't me) for CORE to include the user page as a variable and for that variable to be defined on set up. In that way, CORE would not have to be hacked and the page name would be stored in the data tables rather than hard coded (so no need to hack each update as it is applied). I don't think that would cause significant server load / system slowdown even on large sites.

If I'm right, this would involve a small re-write of a small part of CORE and the installation package (to create a new entry on the tables) and somewhere in the UI for the installer (and, perhaps for later changes, admin) to input the chosen name.

And it takes all the techie stuff away from non-techie users which is why we, amongst millions, chose Drupal.

herojig's picture

Hi all, I just want the user, once logged in, to go to home page instead of the user page. I am using logontoboggin and can't figure it out. The override there does not seem to work for new users, and existing users I have no clue. Please help, as I am stuck in Nepal and there are no drupal techies here :) cheers!

The test site is here:
http://202.52.231.58

Jiggy Gaton, Living in Nepal

Though I didn't use this

gdruckman's picture

Though I didn't use this module myself, but after reading its description it sounds like it may be your solution...
Did you try "Login Destination" http://drupal.org/project/login_destination ?

Also not sure if you're using D6 or D7, maybe this may work for you too http://drupal.org/project/loginlogout

Hope this helps.

herojig's picture

Thx again, login destination is a great simple to use module that plays well with logintoboggin.

Jiggy Gaton, Living in Nepal

Thx!

herojig's picture

Will give those a shot gd!

Jiggy Gaton, Living in Nepal

Rename User Path

ecosnow's picture

Thank you blasthaus for the mod. Can I leave my errors here about this Mod? Thx.

Try the last version

Raphael Apard's picture

Try the last version (7.x-2.0-alpha2).
For errors reporting : http://drupal.org/project/issues/rename_admin_paths

worked in d7 just fine

cdmo's picture

I copied this approach pretty much verbatimin to do change the locations of my login and registration pages and it worked great. I was getting a user logging in and creating an account about once every 5 to 10 minutes, sometimes more often. It stopped. Completely. It's only been a day now, but that's progress. I still have links to the registration and login page from every page on my site too. This combined with LoginToboggan's ability to kill off a user account that doesn't confirm within X time frame is making me feel much better.

Login Url Token

w00zle's picture

Hi all,

Just a fair warning to anyone using the method outlined by Tom Friedhof: this appears to not update the site:login-url token used in emails, etc, so it's possible you will end up with a situation in which your users are getting emails asking them to login at a url that either throws a 404 or 403 depending upon your implementation.

Edit: I should add that I tested the Rename Admin Paths module (https://drupal.org/project/rename_admin_paths) and it does appear to update the token correctly.

High Desert - California

Group organizers

Group categories

Group notifications

This group offers an RSS feed. Or subscribe to these personalized, sitewide feeds: