View | Details | Raw Unified | Return to bug 8753
Collapse All | Expand All

(-)a/C4/Auth.pm (-1 / +3 lines)
Lines 1020-1027 sub checkauth { Link Here
1020
        PatronSelfRegistrationDefaultCategory => C4::Context->preference("PatronSelfRegistrationDefaultCategory"),
1020
        PatronSelfRegistrationDefaultCategory => C4::Context->preference("PatronSelfRegistrationDefaultCategory"),
1021
        persona            => C4::Context->preference("Persona"),
1021
        persona            => C4::Context->preference("Persona"),
1022
        opac_css_override => $ENV{'OPAC_CSS_OVERRIDE'},
1022
        opac_css_override => $ENV{'OPAC_CSS_OVERRIDE'},
1023
        OpacResetPassword => C4::Context->preference("OpacResetPassword"),
1024
        OpacPasswordChange => C4::Context->preference("OpacPasswordChange"),
1023
    );
1025
    );
1024
1026
        
1025
    $template->param( OpacPublic => C4::Context->preference("OpacPublic"));
1027
    $template->param( OpacPublic => C4::Context->preference("OpacPublic"));
1026
    $template->param( loginprompt => 1 ) unless $info{'nopermission'};
1028
    $template->param( loginprompt => 1 ) unless $info{'nopermission'};
1027
1029
(-)a/C4/Members.pm (-1 / +81 lines)
Lines 41-46 use DateTime::Format::DateParse; Link Here
41
use Koha::DateUtils;
41
use Koha::DateUtils;
42
use Text::Unaccent qw( unac_string );
42
use Text::Unaccent qw( unac_string );
43
43
44
## Password recovery
45
use CGI;
46
use Encode qw(encode decode);
47
use MIME::QuotedPrint qw(encode_qp);
48
use Mail::Sendmail;
49
44
our ($VERSION,@ISA,@EXPORT,@EXPORT_OK,$debug);
50
our ($VERSION,@ISA,@EXPORT,@EXPORT_OK,$debug);
45
51
46
BEGIN {
52
BEGIN {
Lines 109-115 BEGIN { Link Here
109
    push @EXPORT, qw(
115
    push @EXPORT, qw(
110
        &ModMember
116
        &ModMember
111
        &changepassword
117
        &changepassword
112
         &ModPrivacy
118
        &ModPrivacy
119
    );
120
    
121
    # Password recovery
122
    push @EXPORT, qw(
123
        &SendPasswordRecoveryEmail
113
    );
124
    );
114
125
115
    #Delete data
126
    #Delete data
Lines 2287-2292 sub ModPrivacy { Link Here
2287
                      privacy        => $privacy );
2298
                      privacy        => $privacy );
2288
}
2299
}
2289
2300
2301
2302
sub SendPasswordRecoveryEmail {
2303
    my $borrowernumber = shift;
2304
    my $email = shift;
2305
    my $dbh = C4::Context->dbh;
2306
    #use constant EMAIL_ENCODE = 'iso-8859-1';
2307
    my $emailEncode = 'iso-8859-1';
2308
    my $username = GetMemberDetails($borrowernumber)->{userid};
2309
2310
    #generate UUID
2311
    my @chars = ("A".."Z", "a".."z", "0".."9");
2312
    my $uuid_str;
2313
    $uuid_str .= $chars[rand @chars] for 1..32;
2314
2315
    #insert into database
2316
    my $sth = $dbh->prepare( 'INSERT INTO borrower_password_recovery VALUES (? ,? , ADDDATE(NOW(), INTERVAL 2 DAY) )' );
2317
    $sth->execute($borrowernumber, $uuid_str);
2318
2319
    my $userEmail = ( $email ) ? $email : GetFirstValidEmailAddress($borrowernumber);
2320
    #define to/from emails
2321
    my $kohaEmail = C4::Context->preference( 'KohaAdminEmailAddress' );
2322
2323
    #create link
2324
    my $uuidLink = "http://" . C4::Context->preference( 'OPACBaseURL' ) . "/cgi-bin/koha/opac-password-recovery.pl?uniqueKey=$uuid_str";
2325
    #warn $uuidLink;
2326
2327
    #build email content
2328
    my $query = new CGI;
2329
    my ( $template2, $borrower_number, $cookie ) = C4::Auth::get_template_and_user(
2330
    {
2331
        template_name   => "opac-send-password-recovery.tmpl",
2332
        query           => $query,
2333
        type            => "opac",
2334
        authnotrequired => 1,
2335
    }
2336
    );
2337
    $template2->param(
2338
        uuidLink         => $uuidLink,
2339
        username         => $username,
2340
    );
2341
2342
    # Getting template result and
2343
    my $template_res = $template2->output();
2344
2345
    #Mail attributes
2346
    my %mail = (
2347
        To  => $userEmail,
2348
        From  => $kohaEmail,
2349
        'Content-Type' => 'text/html; charset="' . $emailEncode . '"',
2350
    );
2351
2352
    #getting mail properties
2353
    if ( $template_res =~ /<SUBJECT>(.*)<END_SUBJECT>/s ) { $mail{'subject'} = decode( 'utf-8', $1 ); }
2354
    if ( $template_res =~ /<MESSAGE>\n(.*)\n<END_MESSAGE>/s ) { $mail{'body'} = decode( 'utf-8', $1 ); }
2355
    #send mail
2356
    if ( sendmail %mail )
2357
    {
2358
        # if it works....
2359
        return 1;
2360
    }
2361
    else
2362
    {
2363
        # if it doesnt work....
2364
        warn "Error sending mail: $Mail::Sendmail::error \n";
2365
        return 0;
2366
    }
2367
}
2368
2369
2290
=head2 AddMessage
2370
=head2 AddMessage
2291
2371
2292
  AddMessage( $borrowernumber, $message_type, $message, $branchcode );
2372
  AddMessage( $borrowernumber, $message_type, $message, $branchcode );
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref (-1 / +8 lines)
Lines 551-557 OPAC: Link Here
551
                  track: "Track"
551
                  track: "Track"
552
                  no: "Don't track"
552
                  no: "Don't track"
553
            - links that patrons click on
553
            - links that patrons click on
554
554
        -
555
            - pref: OpacResetPassword
556
              default: 1
557
              choices:
558
                  yes: "On"
559
                  no: "Off"
560
            - ". If On, the user can reset his password on OPAC."
561
        
555
    Shelf Browser:
562
    Shelf Browser:
556
        -
563
        -
557
            - pref: OPACShelfBrowser
564
            - pref: OPACShelfBrowser
(-)a/koha-tmpl/opac-tmpl/prog/en/modules/opac-auth.tt (+3 lines)
Lines 85-90 please choose against which one you would like to authenticate: </p> Link Here
85
</ol></fieldset>
85
</ol></fieldset>
86
86
87
<input type="submit" value="Log In" class="submit" />
87
<input type="submit" value="Log In" class="submit" />
88
[% IF OpacPasswordChange && OpacResetPassword %]
89
	<p><a href="/cgi-bin/koha/opac-password-recovery.pl">Forgot your password?</a></p>
90
[% END %]
88
<div id="nologininstructions">
91
<div id="nologininstructions">
89
    <h5>Don't have a password yet?</h5><p> If you don't have a password yet, stop by the circulation desk the next time you're in the library. We'll happily set one up for you.</p>
92
    <h5>Don't have a password yet?</h5><p> If you don't have a password yet, stop by the circulation desk the next time you're in the library. We'll happily set one up for you.</p>
90
    <h5>Don't have a library card?</h5><p> If you don't have a library card, stop by your local library to sign up[% IF PatronSelfRegistration && PatronSelfRegistrationDefaultCategory %]<span id="registrationinstructions"> or  <a href="/cgi-bin/koha/opac-memberentry.pl">register here</a></span>[% END %].  </p>
93
    <h5>Don't have a library card?</h5><p> If you don't have a library card, stop by your local library to sign up[% IF PatronSelfRegistration && PatronSelfRegistrationDefaultCategory %]<span id="registrationinstructions"> or  <a href="/cgi-bin/koha/opac-memberentry.pl">register here</a></span>[% END %].  </p>
(-)a/koha-tmpl/opac-tmpl/prog/en/modules/opac-main.tt (-2 / +6 lines)
Lines 59-66 Link Here
59
	 <input type="submit" value="Log In" class="submit" />
59
	 <input type="submit" value="Log In" class="submit" />
60
60
61
        [% IF PatronSelfRegistration && PatronSelfRegistrationDefaultCategory %]<div id="patronregistration">Don't have an account? <a href="/cgi-bin/koha/opac-memberentry.pl">Register here.</a></div>[% END %]
61
        [% IF PatronSelfRegistration && PatronSelfRegistrationDefaultCategory %]<div id="patronregistration">Don't have an account? <a href="/cgi-bin/koha/opac-memberentry.pl">Register here.</a></div>[% END %]
62
62
		
63
	 </fieldset></fieldset>
63
	 </fieldset>
64
	 [% IF OpacPasswordChange && opacResetPassword %]
65
             <p><a href="/cgi-bin/koha/opac-password-recovery.pl">Forgot your password?</a></p>
66
     [% END %]
67
	 </fieldset>
64
	</form>
68
	</form>
65
	</div>
69
	</div>
66
    [% END %]
70
    [% END %]
(-)a/koha-tmpl/opac-tmpl/prog/en/modules/opac-password-recovery.tt (+129 lines)
Line 0 Link Here
1
[% INCLUDE 'doc-head-open.inc' %]
2
[% IF (LibraryNameTitle) %][% LibraryNameTitle %][% ELSE %]Koha Online[% END %] Catalog &rsaquo;  
3
[% INCLUDE 'doc-head-close.inc' %]
4
5
<script type="text/javascript" language="javascript">
6
   $(function() {
7
        $("#CheckAll").click(function(){
8
                $("[name=deleteRequest]").attr('checked', true);
9
                return false;
10
            });
11
12
        $("#CheckNone").click(function(){
13
                $("[name=deleteRequest]").attr('checked', false);
14
                return false;
15
            }); 
16
            
17
        $("select#type").change(function() {
18
            $("fieldset#serial, fieldset#book, fieldset#chapter").hide()
19
            $("fieldset#" + $(this).val() ).show();
20
        });
21
   });
22
</script>
23
</head>
24
<body>
25
26
<div id="doc3" class="yui-t1">
27
    <div id="bd">
28
[% INCLUDE 'masthead.inc' %]
29
        <div id="yui-main">
30
            <div class="yui-b">
31
                <div class="yui-g">
32
                    <div class="illrequest">
33
[% IF (!OpacResetPassword) %]
34
    <div class="dialog alert">You can't reset your password.</div>
35
[% ELSIF (password_recovery) %]
36
    [% IF (hasError) %]
37
        <span class="TxtErreur">
38
        [% IF (sendmailError) %]
39
            An error has occured while sending you the password recovery link.
40
            <br/>Please try again later.
41
        [% ELSIF (errNoEmailFound) %]
42
            No account was found with the email address "<strong>[% email %]</strong>"
43
            <br/>Check if you typed it correctly.
44
        [% ELSIF (errTooManyEmailFound) %]
45
            More than one account has been found for the email address: "<strong>[% email %]</strong>"
46
            <br/>Try yo use your alternative email if you have another.
47
        [% ELSIF (errAlreadyStartRecovery) %]
48
            The process of password recovery has already started for this account ("<strong>[% email %]</strong>")
49
            <br/>Check your emails; you should recieve the link to reset your password.
50
            <br/>If you didn't recieve it, <a href="/cgi-bin/koha/opac-password-recovery.pl?resendEmail=true&email=[% email %]">click here to get a new password recovery link</a>
51
        [% END %]
52
        <br/><br/>Please contact the staff if you need further assistance.
53
        </span>
54
    [% END %]
55
        <div id="password-recovery" class="container">
56
            <form action="/cgi-bin/koha/opac-password-recovery.pl" method="post">
57
                <input type="hidden" name="koha_login_context" value="opac" />
58
                <fieldset class="brief">
59
                    <legend>Password recovery form:</legend>
60
                        <p>To reset your password, enter your email address.
61
                        <br/>A link to reset your password will be sent at this address.</p>
62
                        <ol>
63
                            <li><label for="email">Email:</label><input type="text" id="email" size="40" name="email" value="[% email %]" /></li>
64
                        </ol>
65
                    <fieldset class="action">
66
                 <input type="submit" value="Submit" class="submit" name="sendEmail" />
67
                    </fieldset>
68
                 </fieldset>
69
            </form>
70
        </div>
71
72
[% ELSIF (new_password) %]
73
    [% IF (errLinkNotValid) %]
74
        <span class="TxtErreur"><h6>
75
        We could not authentify you as the account owner.
76
        <br/>Be sure to use the link you recieved in your email.
77
        </h6></span>
78
    [% ELSE %]
79
        [% IF (hasError) %]
80
            <span class="TxtErreur">
81
            [% IF (errPassNotMatch) %]
82
                The passwords entered does not match.
83
                <br/>Please try again.
84
            [% ELSIF (errPassTooShort) %]
85
                The password is too short.
86
                <br/>The password must contain at least [% minPassLength %] characters.
87
            [% END %]
88
            </span>
89
        [% END %]
90
            <div id="password-recovery" class="container">
91
                <form action="/cgi-bin/koha/opac-password-recovery.pl" method="post">
92
                    <input type="hidden" name="koha_login_context" value="opac" />
93
                    <fieldset class="brief">
94
                        <legend>Password recovery form:</legend>
95
                            <p class="light">The password must contain at least [% minPassLength %] characters.</p>
96
                            <ol>
97
                                <li><label for="password">New password:</label><input type="password" id="password" size="40" name="password" /></li>
98
                                <li><label for="repeatPassword">Confirm new password:</label><input type="password" id="repeatPassword" size="40" name="repeatPassword" /></li>
99
                            </ol>
100
                        <fieldset class="action">
101
                        <input type="hidden" name="username" value="[% username %]" />
102
                        <input type="hidden" name="uniqueKey" value="[% uniqueKey %]" />
103
                        <input type="submit" value="Submit" class="submit" name="passwordReset" />
104
                        </fieldset>
105
                     </fieldset>
106
                </form>
107
            </div>
108
    [% END %]
109
[% ELSIF (mail_sent) %]
110
    <p>A mail has been sent to "[% email %]".
111
    <br/>It contains a link to create a new password.
112
    <br/>This link will be valid for 2 days from now.</p>
113
    <br/><a href="/cgi-bin/koha/opac-main.pl"">Click here to return to the main page.</a>
114
[% ELSIF (password_reset_done) %]
115
    <p>The password has been changed for the user "[% username %]".
116
    <br/>You can now login using <a href="/cgi-bin/koha/opac-user.pl">this form</a>.</p>
117
[% END %]
118
                    </div>
119
                </div>
120
            </div>
121
        </div>
122
        <div class="yui-b">
123
            <div class="container">
124
                [% INCLUDE 'usermenu.inc' %]
125
            </div>
126
        </div>
127
    </div>
128
[% INCLUDE 'opac-bottom.inc' %]
129
</div>
(-)a/koha-tmpl/opac-tmpl/prog/en/modules/opac-send-password-recovery.tt (+13 lines)
Line 0 Link Here
1
<SUBJECT>[% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha Online[% END %] - Password recovery<END_SUBJECT>
2
3
<MESSAGE>
4
<html>
5
<p>This email has been sent in response to your password recovery request for the account <strong>[% username %]</strong>.</p>
6
<p>
7
You can now create your new password using the following link:
8
<br/><a href="[% uuidLink %]">[% uuidLink %]</a>
9
</p>
10
<p>This link will be valid for 2 days from this email's reception, then you must reapply if you do not change your password.</p>
11
<p>Thank you.</p>
12
</html>
13
<END_MESSAGE>
(-)a/opac/opac-main.pl (+1 lines)
Lines 58-63 $template->param( Link Here
58
    koha_news_count     => $koha_news_count,
58
    koha_news_count     => $koha_news_count,
59
    display_daily_quote => C4::Context->preference('QuoteOfTheDay'),
59
    display_daily_quote => C4::Context->preference('QuoteOfTheDay'),
60
    daily_quote         => $quote,
60
    daily_quote         => $quote,
61
    opacResetPassword   => C4::Context->preference('OpacResetPassword'),
61
);
62
);
62
63
63
# If GoogleIndicTransliteration system preference is On Set paramter to load Google's javascript in OPAC search screens
64
# If GoogleIndicTransliteration system preference is On Set paramter to load Google's javascript in OPAC search screens
(-)a/opac/opac-password-recovery.pl (-1 / +224 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/perl
2
3
use strict;
4
5
use CGI;
6
use Mail::Sendmail;
7
use Digest::MD5 qw(md5_base64);
8
use HTML::Entities;
9
10
use C4::Auth;
11
use C4::Koha;
12
use C4::Members qw(changepassword GetMember GetMemberDetails SendPasswordRecoveryEmail);
13
use C4::Output;
14
use C4::Context;
15
16
my $query = new CGI;
17
18
my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
19
    {
20
        template_name   => "opac-password-recovery.tmpl",
21
        query           => $query,
22
        type            => "opac",
23
        authnotrequired => 1,
24
        debug           => 1,
25
    }
26
);
27
28
my $email           = $query->param('email');
29
my $password        = $query->param('password');
30
my $repeatPassword  = $query->param('repeatPassword');
31
my $minPassLength   = C4::Context->preference( 'minPasswordLength' );
32
my $id              = $query->param('id');
33
my $uniqueKey       = $query->param('uniqueKey');
34
my $username        = $query->param('username');
35
my $borrower_number;
36
37
#errors
38
my $hasError;
39
40
#email form error
41
my $errNoEmailFound;
42
my $errAlreadyStartRecovery;
43
44
#new password form error
45
my $errLinkNotValid;
46
my $errPassNotMatch;
47
my $errPassTooShort;
48
49
my $dbh = C4::Context->dbh;
50
51
$template->param( OpacResetPassword => C4::Context->preference("OpacResetPassword") );
52
53
if ( $query->param('sendEmail') || $query->param('resendEmail') )
54
{
55
#send mail + confirmation
56
57
    #try with the main email
58
    my $borrower_number;
59
    my $accountActivated;
60
    my %borrower_infos  = GetMember(email => $email);
61
    if ( %borrower_infos )
62
    {
63
        $borrower_number = GetMember(email => $email)->{'borrowernumber'};
64
        $username        = GetMemberDetails( $borrower_number )->{'userid'};
65
        $accountActivated = ( GetMemberDetails( $borrower_number )->{'categorycode'} ne 'UNAUTHORIZ' ) ? 1 : 0;
66
    }
67
    else
68
    {
69
        #try with the secondary email
70
        %borrower_infos  = GetMember(emailpro => $email);
71
        if ( %borrower_infos )
72
        {
73
            $borrower_number = GetMember(emailpro => $email)->{'borrowernumber'};
74
            $username        = GetMemberDetails( $borrower_number )->{'userid'};
75
            $accountActivated = ( GetMemberDetails( $borrower_number )->{'categorycode'} ne 'UNAUTHORIZ' ) ? 1 : 0;
76
        }
77
        else
78
        {
79
            #try when the other contact email
80
            %borrower_infos  = GetMember(B_email => $email);
81
            if ( %borrower_infos )
82
            {
83
                $borrower_number = GetMember(B_email => $email)->{'borrowernumber'};
84
                $username        = GetMemberDetails( $borrower_number )->{'userid'};
85
                $accountActivated = ( GetMemberDetails( $borrower_number )->{'categorycode'} ne 'UNAUTHORIZ' ) ? 1 : 0;
86
            }
87
        }
88
    }
89
    
90
    if ( !$email || !$username || !$borrower_number || !$accountActivated )
91
    {
92
        $hasError = 1;
93
        $errNoEmailFound = 1;
94
    }
95
    elsif ( !$query->param('resendEmail') )
96
    {
97
        my $sth = $dbh->prepare( "SELECT borrowernumber FROM borrower_password_recovery WHERE NOW() < valid_until AND borrowernumber = ?" );
98
        $sth->execute($borrower_number);
99
        if ( my $already = $sth->fetchrow )
100
        {
101
            $hasError = 1;
102
            $errAlreadyStartRecovery = 1;
103
        }
104
    }
105
    
106
    if ( $hasError )
107
    {
108
        $template->param(             hasError => 1,
109
                               errNoEmailFound => $errNoEmailFound,
110
                       errAlreadyStartRecovery => $errAlreadyStartRecovery,
111
                             password_recovery => 1,
112
                                         email => HTML::Entities::encode($email),
113
        );
114
    }
115
    else
116
    {
117
        #generate uuid and send recovery email
118
        if ( SendPasswordRecoveryEmail($borrower_number, $email) )
119
        {
120
			# if it works....
121
            $template->param(   mail_sent => 1,
122
                                    email => $email
123
            );
124
        }
125
        else
126
        {
127
			# if it doesnt work....
128
			$template->param( password_recovery => 1,
129
			                      sendmailError => 1 
130
			);
131
        }
132
    }
133
}
134
elsif ( $query->param('passwordReset') )
135
{
136
#new password form
137
    #check if the link is still valid
138
    my $sth = $dbh->prepare( "SELECT borrower_password_recovery.borrowernumber, userid 
139
                              FROM borrower_password_recovery, borrowers 
140
                              WHERE borrowers.borrowernumber = borrower_password_recovery.borrowernumber 
141
                              AND NOW() < valid_until 
142
                              AND uuid = ?" );
143
    $sth->execute( $uniqueKey );
144
    ( $borrower_number , $username) = $sth->fetchrow;
145
146
    #validate password length & match
147
    if ( ( $borrower_number ) && ( $password eq $repeatPassword ) && ( length( $password ) >= $minPassLength ) )
148
    {
149
        #apply changes
150
        changepassword( $username, $borrower_number, md5_base64($password) ); 
151
        #this line needed to fix a log bug in "Log.pm:75"
152
        #
153
        #       if ( !$usernumber ) {  $usernumber=0; }
154
        #
155
        
156
        #remove entry
157
        my $sth = $dbh->prepare( "DELETE FROM borrower_password_recovery
158
                                  WHERE uuid = ?
159
                                  ORDER BY valid_until DESC LIMIT 1" );
160
        $sth->execute( $uniqueKey);
161
        
162
        $template->param( password_reset_done => 1,
163
                                     username => $username
164
        );
165
    }
166
    else
167
    {
168
        #errors
169
        if ( !$borrower_number )
170
        {
171
            #parameters not valid
172
            $errLinkNotValid = 1;
173
        }
174
        elsif ( $password ne $repeatPassword )
175
        {
176
            #passwords does not match
177
            $errPassNotMatch = 1;
178
        }
179
        elsif ( length( $password ) < $minPassLength )
180
        {
181
            #password too short
182
            $errPassTooShort = 1;
183
        }
184
        $template->param( new_password => 1,
185
                         minPassLength => $minPassLength,
186
                                 email => $email,
187
                             uniqueKey => $uniqueKey,
188
                       errLinkNotValid => $errLinkNotValid,
189
                       errPassNotMatch => $errPassNotMatch,
190
                       errPassTooShort => $errPassTooShort,
191
                              hasError => 1 );
192
    }
193
}
194
elsif ( $uniqueKey )
195
{
196
#reset password form 
197
    #check if the link is valid
198
    my $sth = $dbh->prepare( "SELECT borrower_password_recovery.borrowernumber, userid 
199
                              FROM borrower_password_recovery, borrowers 
200
                              WHERE borrowers.borrowernumber = borrower_password_recovery.borrowernumber 
201
                              AND NOW() < valid_until 
202
                              AND uuid = ?" );
203
    $sth->execute( $uniqueKey );
204
    ( $borrower_number, $username ) = $sth->fetchrow;
205
    if( !$borrower_number )
206
    {
207
        $errLinkNotValid = 1;
208
    }
209
    $template->param( new_password => 1,
210
                     minPassLength => $minPassLength,
211
                             email => $email,
212
                         uniqueKey => $uniqueKey,
213
                          username => $username,
214
                   errLinkNotValid => $errLinkNotValid 
215
   );
216
}
217
else
218
{
219
    #password recovery form (to send email)
220
    $template->param( password_recovery => 1 );
221
}
222
223
output_html_with_http_headers $query, $cookie, $template->output;
224

Return to bug 8753