EmulabTemplateLogin.pm 6.91 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
# Module of TWiki Enterprise Collaboration Platform, http://TWiki.org/
#
# Copyright (C) 2005-2006 TWiki Contributors. All Rights Reserved.
# TWiki Contributors
# are listed in the AUTHORS file in the root of this distribution.
# NOTE: Please extend that file, not this notice.
#
# Additional copyrights apply to some or all of the code in this
# file as follows:
# Copyright (C) 2005 Greg Abbas, twiki@abbas.org
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. For
# more details read LICENSE in the root of this distribution.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# As per the GPL, removal of this notice is prohibited.

=pod

---+ package TWiki::Client::EmulabTemplateLogin

This is a login manager that you can specify in the security setup section of [[%SCRIPTURL%/configure%SCRIPTSUFFIX%][configure]]. It provides users with a template-based form to enter usernames and passwords, and works with the PasswordManager that you specify to verify those passwords.

Subclass of TWiki::Client; see that class for documentation of the
methods of this class.

=cut

package TWiki::Client::EmulabTemplateLogin;

use strict;
use Assert;
use TWiki::Client;

@TWiki::Client::EmulabTemplateLogin::ISA = ( 'TWiki::Client' );

sub new {
    my( $class, $session ) = @_;

    my $this = bless( $class->SUPER::new($session), $class );
    $session->enterContext( 'can_login' );
    return $this;
}

# Triggered on auth fail
sub forceAuthentication {
    my $this = shift;
    my $twiki = $this->{twiki};

    unless( $twiki->inContext( 'authenticated' )) {
        my $query = $twiki->{cgiQuery};
        # SMELL CGI::url drops the anchor. Report as bug against CGI::?
        $query->param( origurl => $query->url( -path => 1, -query => 1 ));
        $this->login( $query, $twiki );
        return 1;
    }
    return undef;
}

# Content of a login link
sub loginUrl {
    my $this = shift;
    my $twiki = $this->{twiki};
    my $topic = $twiki->{topicName};
    my $web = $twiki->{webName};
    my $query = $twiki->{cgiQuery};
    return $twiki->getScriptUrl( 0, 'login', $web, $topic,
                                 origurl => $query->url( -path => 1,
                                                         -query => 1 ), @_ );
}

sub findwikiname {
    my ($loginUser) = @_;
    
    if (!$loginUser) {
        return "";
    }
    my $wikiname;
    my $datadir = $TWiki::cfg{DataDir};
    my %MAPDB   = ();
	
    if (dbmopen(%MAPDB, "${datadir}/.usermap", 0644)) {
	if (defined($MAPDB{$loginUser})) {
	    $wikiname = $MAPDB{$loginUser};
	}
	dbmclose(%MAPDB);
    }
    return $loginUser
	if (!defined($wikiname));

    return $wikiname;
}

=pod

---++ ObjectMethod login( $query, $twiki )

If a login name and password have been passed in the query, it
validates these and if authentic, redirects to the original
script. If there is no username in the query or the username/password is
invalid (validate returns non-zero) then it prompts again.

The password handler is expected to return a perl true value if the password
is valid. This return value is stored in a session variable called
VALIDATION. This is so that password handlers can return extra information
about the user, such as a list of TWiki groups stored in a separate
database, that can then be displayed by referring to
%<nop>SESSION_VARIABLE{"VALIDATION"}%

=cut

sub login {
    my( $this, $query, $twikiSession ) = @_;
    my $twiki = $this->{twiki};

    my $origurl = $query->param( 'origurl' );
    my $loginName = $query->param( 'username' );
    my $loginPass = $query->param( 'password' );
    my $bosscred  = $query->param( 'bosscred' );

    my $tmpl = $twiki->{templates}->readTemplate(
        'login', $twiki->getSkin() );

    my $banner = $twiki->{templates}->expandTemplate( 'LOG_IN_BANNER' );
    my $note = '';
    my $topic = $twiki->{topicName};
    my $web = $twiki->{webName};

    my $cgisession = $this->{cgisession};

    if( $cgisession && $cgisession->param( 'AUTHUSER' ) &&
          $loginName ne $cgisession->param( 'AUTHUSER' )) {
        $banner = $twiki->{templates}->expandTemplate( 'LOGGED_IN_BANNER' );
        $note = $twiki->{templates}->expandTemplate( 'NEW_USER_NOTE' );
    }

    #
    # If bosscred provided, boss is trying to autologin the user using
    # a key that it sent across via a backend script and stashed in the
    # cookie dir. Find that file, compare the keys and if the key is not
    # too terribly old, give the user the nod.
    #
    if ($bosscred) {
	if (!$loginName || $loginName eq "") {
	    return undef;
	}
	$banner = $twiki->{templates}->expandTemplate('UNRECOGNISED_USER');
	my $CREDDIR = "/var/db/cgisess";
	my $file    = "${CREDDIR}/$loginName";

	if (! -e $file) {
	    $twiki->writeWarning("Cred file $file does not exist!");
	    goto denied;
	}
	if (!open(COK, $file)) {
	    $twiki->writeWarning("Cannot open cred file $file!");
	    goto denied;
	}
	my $cred  = <COK>;
	my $stamp = <COK>;
	close(COK);

	# Compare credentials.
	if ($cred) {
	    chomp($cred);
	    if ($cred eq $bosscred) {
		#
		# Find the wikiname.
		#
		my $wikiname = findwikiname($loginName);
		my $redurl   = $query->param('redurl');
		
		$this->userLoggedIn($wikiname);
		$cgisession->param( 'VALIDATION', 1 ) if $cgisession;
		
		if( !$redurl || $redurl eq $query->url() ) {
		    $redurl = $twiki->getScriptUrl( 0, 'view', $web, $topic );
		}
		else {
		    $redurl = $twiki->getScriptUrl( 0, 'view', $web, $redurl );
		}
		
		$this->redirectCgiQuery( $query, $redurl );
		return;
	    }
	}
	# Does not match.
	$twiki->writeWarning("cred mismatch for $loginName; $cred,$bosscred!");
	goto denied;
    }

    if( $loginName ) {
        my $passwordHandler = $twiki->{users}->{passwords};
        my $validation = $passwordHandler->checkPassword( $loginName, $loginPass );

        if( $validation ) {
            $this->userLoggedIn( $loginName );
            $cgisession->param( 'VALIDATION', $validation ) if $cgisession;
            if( !$origurl || $origurl eq $query->url() ) {
                $origurl = $twiki->getScriptUrl( 0, 'view', $web, $topic );
            }
            $this->redirectCgiQuery( $query, $origurl );
            return;
        } else {
            $banner = $twiki->{templates}->expandTemplate('UNRECOGNISED_USER');
        }
    }
  denied:

    # TODO: add JavaScript password encryption in the template
    # to use a template)
    $origurl ||= '';
    $tmpl =~ s/%ORIGURL%/$origurl/g;
    $tmpl =~ s/%BANNER%/$banner/g;
    $tmpl =~ s/%NOTE%/$note/g;

    $tmpl = $twiki->handleCommonTags( $tmpl, $web, $topic );
    $tmpl = $twiki->{renderer}->getRenderedVersion( $tmpl, '' );
    $tmpl =~ s/<nop>//g;
    $twiki->writePageHeader( $query );
    print $tmpl;
}

1;