File Coverage

blib/lib/CGI/Application/Plugin/Authentication/Display/Classic.pm
Criterion Covered Total %
statement 86 86 100.0
branch 54 54 100.0
condition 13 14 92.8
subroutine 8 8 100.0
pod 2 2 100.0
total 163 164 99.3


line stmt bran cond sub pod time code
1             package CGI::Application::Plugin::Authentication::Display::Classic;
2             $CGI::Application::Plugin::Authentication::Display::Classic::VERSION = '0.21';
3 14     14   810 use base qw(CGI::Application::Plugin::Authentication::Display);
  14         18  
  14         5594  
4              
5 14     14   188 use 5.006;
  14         33  
6 14     14   57 use strict;
  14         17  
  14         210  
7 14     14   48 use warnings;
  14         14  
  14         255  
8 14     14   49 use Carp;
  14         13  
  14         15387  
9              
10             sub new {
11 60     60 1 83 my $class = shift;
12 60         69 my $cgiapp = shift;
13 60         232 my $self = CGI::Application::Plugin::Authentication::Display->new($cgiapp);
14 60         95 bless $self, $class;
15 60         132 return $self;
16             }
17              
18             sub login_box {
19 72     72 1 102 my $self = shift;
20 72         214 my $credentials = $self->_cgiapp->authen->credentials;
21 72         197 my $runmode = $self->_cgiapp->get_current_runmode;
22 72   100     361 my $destination = $self->_cgiapp->authen->_detaint_destination || $self->_cgiapp->authen->_detaint_selfurl;
23 72         258 my $action = $self->_cgiapp->authen->_detaint_url;
24 72         138 my $username = $credentials->[0];
25 72         104 my $password = $credentials->[1];
26 72   100     192 my $login_form = $self->_cgiapp->authen->_config->{LOGIN_FORM} || {};
27 72         1144 my %options = (
28             TITLE => 'Sign In',
29             USERNAME_LABEL => 'User Name',
30             PASSWORD_LABEL => 'Password',
31             SUBMIT_LABEL => 'Sign In',
32             COMMENT => 'Please enter your username and password in the fields below.',
33             REMEMBERUSER_OPTION => 1,
34             REMEMBERUSER_LABEL => 'Remember User Name',
35             REMEMBERUSER_COOKIENAME => 'CAPAUTHTOKEN',
36             REGISTER_URL => '',
37             REGISTER_LABEL => 'Register Now!',
38             FORGOTPASSWORD_URL => '',
39             FORGOTPASSWORD_LABEL => 'Forgot Password?',
40             INVALIDPASSWORD_MESSAGE => 'Invalid username or password
(login attempt %d)',
41             INCLUDE_STYLESHEET => 1,
42             FORM_SUBMIT_METHOD => 'post',
43             %$login_form,
44             );
45              
46 72         115 my $messages = '';
47 72 100       193 if ( my $attempts = $self->_cgiapp->authen->login_attempts ) {
    100          
48 42         233 $messages .= '
  • ' . sprintf($options{INVALIDPASSWORD_MESSAGE}, $attempts) . '
  • ';
    49             } elsif ($options{COMMENT}) {
    50 29         77 $messages .= "
  • $options{COMMENT}
  • ";
    51             }
    52              
    53 72         99 my $tabindex = 3;
    54 72         427 my ($rememberuser, $username_value, $register, $forgotpassword, $javascript, $style) = ('','','','','','');
    55 72 100       174 if ($options{FOCUS_FORM_ONLOAD}) {
    56 1         3 $javascript .= "document.loginform.${username}.focus();\n";
    57             }
    58 72 100       160 if ($options{REMEMBERUSER_OPTION}) {
    59 71         178 $rememberuser = qq[$options{REMEMBERUSER_LABEL}
    ];
    60 71         89 $tabindex++;
    61 71         180 $username_value = $self->_cgiapp->authen->_detaint_username($username, $options{REMEMBERUSER_COOKIENAME});
    62 71 100       230 $javascript .= "document.loginform.${username}.select();\n" if $username_value;
    63             }
    64 72         105 my $submit_tabindex = $tabindex++;
    65 72 100       171 if ($options{REGISTER_URL}) {
    66 1         5 $register = qq[$options{REGISTER_LABEL}];
    67 1         3 $tabindex++;
    68             }
    69 72 100       203 if ($options{FORGOTPASSWORD_URL}) {
    70 1         6 $forgotpassword = qq[$options{FORGOTPASSWORD_LABEL}];
    71 1         1 $tabindex++;
    72             }
    73 72 100       149 if ($options{INCLUDE_STYLESHEET}) {
    74 69         149 my $login_styles = $self->_login_styles;
    75 69         361 $style = <
    76            
    81             EOS
    82             }
    83 72 100       1708 if ($javascript) {
    84 42         96 $javascript = qq[];
    85             }
    86              
    87 72         1144 my $html .= <
    88             $style
    89            
    90            
    91            
    92             $options{TITLE}
    93            
    94            
    95            
    96             ${messages}
    97            
    98            
    99            
    100            
    101            
    102            
    103             ${rememberuser}
    104            
    105            
    106            
    107            
    108            
    109             ${register}
    110             ${forgotpassword}
    111            
    112            
    113            
    114            
    115            
    116            
    117             $javascript
    118             END
    119              
    120 72         797 return $html;
    121             }
    122              
    123             sub _login_styles {
    124 69     69   113 my $self = shift;
    125 69   100     168 my $login_form = $self->_cgiapp->authen->_config->{LOGIN_FORM} || {};
    126 69         136 my %colour = ();
    127              
    128 69   100     328 $colour{base} = $login_form->{BASE_COLOUR} || '#445588';
    129 69 100       975 $colour{lighter} = $login_form->{LIGHTER_COLOUR} if $login_form->{LIGHTER_COLOUR};
    130 69 100       148 $colour{light} = $login_form->{LIGHT_COLOUR} if $login_form->{LIGHT_COLOUR};
    131 69 100       145 $colour{dark} = $login_form->{DARK_COLOUR} if $login_form->{DARK_COLOUR};
    132 69 100       132 $colour{darker} = $login_form->{DARKER_COLOUR} if $login_form->{DARKER_COLOUR};
    133 69 100       141 $colour{grey} = $login_form->{GREY_COLOUR} if $login_form->{GREY_COLOUR};
    134            
    135 69 100       117 my @undefined_colours = grep { ! defined $colour{$_} || index($colour{$_}, '%') >= 0 } qw(lighter light dark darker);
      276         730  
    136 69 100       144 if (@undefined_colours) {
    137 68         90 eval { require Color::Calc };
      68         5723  
    138 68 100 66     343130 if ($@ && $login_form->{BASE_COLOUR}) {
    139 1         16 warn "Color::Calc is required when specifying a custom BASE_COLOUR, and leaving LIGHTER_COLOUR, LIGHT_COLOUR, DARK_COLOUR or DARKER_COLOUR blank or when providing percentage based colour";
    140             }
    141 68 100       197 if ($@) {
    142 2         5 $colour{base} = '#445588';
    143 2         3 $colour{lighter} = '#d0d5e1';
    144 2         4 $colour{light} = '#a2aac4';
    145 2         5 $colour{dark} = '#303c5f';
    146 2         3 $colour{darker} = '#1b2236';
    147 2         5 $colour{grey} = '#565656';
    148             } else {
    149             $colour{lighter} = !$colour{lighter}
    150             ? Color::Calc::light_html($colour{base}, 0.75)
    151             : $colour{lighter} =~ m#(\d{2})%#
    152             ? Color::Calc::light_html($colour{base}, $1 / 100)
    153 66 100       373 : $colour{lighter};
        100          
    154             $colour{light} = !$colour{light}
    155             ? Color::Calc::light_html($colour{base}, 0.5)
    156             : $colour{light} =~ m#(\d{2})%#
    157             ? Color::Calc::light_html($colour{base}, $1 / 100)
    158 66 100       13267 : $colour{light};
        100          
    159             $colour{dark} = !$colour{dark}
    160             ? Color::Calc::dark_html($colour{base}, 0.3)
    161             : $colour{dark} =~ m#(\d{2})%#
    162             ? Color::Calc::dark_html($colour{base}, $1 / 100)
    163 66 100       6710 : $colour{dark};
        100          
    164             $colour{darker} = !$colour{darker}
    165             ? Color::Calc::dark_html($colour{base}, 0.6)
    166             : $colour{darker} =~ m#(\d{2})%#
    167             ? Color::Calc::dark_html($colour{base}, $1 / 100)
    168 66 100       6182 : $colour{darker};
        100          
    169             #$colour{grey} ||= Color::Calc::bw_html($colour{base});
    170 66 100       5944 if (!$colour{grey}) {
    171 61         161 $colour{grey} = Color::Calc::bw_html($colour{base});
    172             }
    173             }
    174             }
    175 69   100     3017 $colour{grey} ||= '#565656';
    176 69         1472 return <
    177             div.login {
    178             width: 25em;
    179             margin: auto;
    180             padding: 3px;
    181             font-weight: bold;
    182             border: 2px solid $colour{base};
    183             color: $colour{dark};
    184             font-family: sans-serif;
    185             }
    186             div.login div {
    187             margin: 0;
    188             padding: 0;
    189             border: none;
    190             }
    191             div.login .login_header {
    192             background: $colour{base};
    193             border-bottom: 1px solid $colour{darker};
    194             height: 1.5em;
    195             padding: 0.45em;
    196             text-align: left;
    197             color: #fff;
    198             font-size: 100%;
    199             font-weight: bold;
    200             }
    201             div.login .login_content {
    202             background: $colour{lighter};
    203             padding: 0.8em;
    204             border-top: 1px solid white;
    205             border-bottom: 1px solid $colour{grey};
    206             font-size: 80%;
    207             }
    208             div.login .login_footer {
    209             background: $colour{light};
    210             border-top: 1px solid white;
    211             border-bottom: 1px solid white;
    212             text-align: left;
    213             padding: 0;
    214             margin: 0;
    215             min-height: 2.8em;
    216             }
    217             div.login fieldset {
    218             margin: 0;
    219             padding: 0;
    220             border: none;
    221             width: 100%;
    222             }
    223             div.login label {
    224             clear: left;
    225             float: left;
    226             padding: 0.6em 1em 0.6em 0;
    227             width: 8em;
    228             text-align: right;
    229             }
    230             /* image courtesy of http://www.famfamfam.com/lab/icons/silk/ */
    231             #authen_loginfield {
    232             background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAG5SURBVHjaYvz//z8DJQAggFiIVfh0twHn9w8KD9+/ZBT+9/cfExfvwwc87GxWAAFEtAFf3yl++/9XikHXL56BkYmJ4dKmcoUPT99PBQggRmK8ALT9v4BUBQMLrxxQMztY7N+PjwyXtk76BxBATMRoFjGewsDCx8jw9Oxyht9vboIxCDAxs/wCCCC8LoBrZv/A8PPpVoZ/39gZ7p57xcDLJ8Xw5tkdBrO8DYwAAcRElOYXaxn+/73DwC4vzyAmzsLw58kJsGaQOoAAYiJK868nDGwSXgxvjp1n+Hz7HoNawRFGmFqAAMIw4MBEDaI1gwBAAKEYsKtL/b9x2HSiNYMAQACBA3FmiqKCohrbfQ2nLobn97Yz6Br/JEozCAAEEDgh/eb6d98yYhEDBxsnw5VNZxnOffjLIKltw/D52B6GH89fMVjUnGbEFdgAAQRPiexMzAyfDk9gMJbmYbh17irDueMrGbjExBi8Oy8z4ksnAAEENuDY1S8MjjsnMSgaezJ8Z2Bm+P95PgPX6ycENYMAQACBwyDSUeQ/GzB926kLMEjwsjOwifKvcy05EkxMHgEIIEZKszNAgAEA+j3MEVmacXUAAAAASUVORK5CYII=') no-repeat 0 1px;
    233             background-color: #fff;
    234             border-top: solid 1px $colour{grey};
    235             border-left: solid 1px $colour{grey};
    236             border-bottom: solid 1px $colour{light};
    237             border-right: solid 1px $colour{light};
    238             padding: 2px 0 2px 18px;
    239             margin: 0.3em 0;
    240             width: 12em;
    241             }
    242             /* image courtesy of http://www.famfamfam.com/lab/icons/silk/ */
    243             #authen_passwordfield {
    244             background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAKbSURBVHjaYvz//z8DPvBko+s0IJUJ5U6X8d+dhSwPEEAMIANw4ccbXKYB8f8/P+6BMYgNEkNWAxBAhDV/Pff/5+t5/39/2gcU/gc25P5qpzkwdQABxIjNCzBnS7p2Mfz5tJ+BkVWE4dWRxWA5oBcYHiyyYnj5heGAedYxR4AAwmXAf0mPWQx/3q9n+P/3I9AAMaCoBsPr4x0MDH/+MUgHrGG4P8eF4fVf9gMAAcSEK/D+/3oA1gxm/3kLJG8wSDhWMAjoeTJ8fxjNoJDQzyD0+7sDQACx4DKAkVWcgZGZG2jIV6AJfxn+/37F8OfPO6BhRxl+f/nIwC7xluHPm58MAAHEhMX5ILHp787OYvj/7zvDr7f7Gf59vw804DUwPM4x/P3+loFb0ZfhVlc1wxMu7psAAcSCEd9MjAzswoYMAppmDD9e9DKwcIkwMHFyMPx+dZnh7+9vDDxqwQx3Ji1jeMrJc9W1/JQOQAAheyFT2mctw9+vpxh+fz7A8O1JDQMrEz/QK2YMb47uZpD0SmEAmsRwu7eJ4QUX1wWXklOGIE0AAcQIim9YShOzSmf49W4xw5+PdxlYeIUYWLh9GS6vXPH+3U/Gd3K/vikzcTAzvOTkOmNXeNIUZitAALFAbF4D9N8Bhl+vJjP8/vCUgY1fkoGZ24PhysoV7178Y9vmW3M8FqZBHS3MAAIIZMDnP59P835/3Mnw98t7Bg5xNQZGNnOgzSvfv2ZgX+dbfiwVX14BCCCQAbyMrNwMDKxcDOxi/Az/WU0YLi1b8/E9K8cqr6JjGQwEAEAAMf378+/cn+//GFi5bRiYuMOBzt7w4RMH50IPIjSDAEAAsbz8+Gfdh9VFEr9//WX7//s/009uzlmuWUcqGYgEAAEGAIZWUhP4bjW1AAAAAElFTkSuQmCC') no-repeat 0 1px;
    245             background-color: #fff;
    246             border-top: solid 1px $colour{grey};
    247             border-left: solid 1px $colour{grey};
    248             border-bottom: solid 1px $colour{light};
    249             border-right: solid 1px $colour{light};
    250             padding: 2px 0 2px 18px;
    251             margin: 0.3em 0;
    252             width: 12em;
    253             }
    254             #authen_rememberuserfield {
    255             clear: left;
    256             margin-left: 8em;
    257             }
    258             #authen_loginfield:focus {
    259             background-color: #ffc;
    260             color: #000;
    261             }
    262             #authen_passwordfield:focus {
    263             background-color: #ffc;
    264             color: #000;
    265             }
    266             div.login a {
    267             font-size: 80%;
    268             color: $colour{dark};
    269             }
    270             div.login div.buttons input {
    271             border-top: solid 2px $colour{light};
    272             border-left: solid 2px $colour{light};
    273             border-bottom: solid 2px $colour{grey};
    274             border-right: solid 2px $colour{grey};
    275             background-color: $colour{lighter};
    276             padding: .2em 1em ;
    277             font-size: 80%;
    278             font-weight: bold;
    279             color: $colour{dark};
    280             }
    281             div.login div.buttons {
    282             display: block;
    283             margin: 8px 4px;
    284             width: 100%;
    285             }
    286             #authen_loginbutton {
    287             float: right;
    288             margin-right: 1em;
    289             }
    290             #authen_registerlink {
    291             display: block;
    292             }
    293             #authen_forgotpasswordlink {
    294             display: block;
    295             }
    296             ul.message {
    297             margin-top: 0;
    298             margin-bottom: 0;
    299             list-style: none;
    300             }
    301             ul.message li {
    302             text-indent: -2em;
    303             padding: 0px;
    304             margin: 0px;
    305             font-style: italic;
    306             }
    307             ul.message li.warning {
    308             color: red;
    309             }
    310             END
    311             }
    312              
    313             =head1 NAME
    314              
    315             CGI::Application::Plugin::Authentication::Display::Classic - login box that works out of the box
    316              
    317             =head1 DESCRIPTION
    318              
    319             This module provides a login box that works out of the box but which can be
    320             configured to modify the styling.
    321              
    322             =head1 METHODS
    323              
    324             =head2 new
    325              
    326             The constructor must be passed the L object as the first
    327             non-object argument.
    328              
    329             =head2 login_box
    330              
    331             This method will return the HTML for a login box that can be
    332             embedded into another page. This is the same login box that is used
    333             in the default authen_login runmode that the plugin provides.
    334              
    335             You can set this option to customize the login form that is created when a user
    336             needs to be authenticated. If you wish to replace the entire login form with a
    337             completely custom version, then just set LOGIN_RUNMODE to point to your custom
    338             runmode.
    339              
    340             All of the parameters listed below are optional, and a reasonable default will
    341             be used if left blank:
    342              
    343             =over 4
    344              
    345             =item TITLE (default: Sign In)
    346              
    347             the heading at the top of the login box
    348              
    349             =item USERNAME_LABEL (default: User Name)
    350              
    351             the label for the user name input
    352              
    353             =item PASSWORD_LABEL (default: Password)
    354              
    355             the label for the password input
    356              
    357             =item SUBMIT_LABEL (default: Sign In)
    358              
    359             the label for the submit button
    360              
    361             =item COMMENT (default: Please enter your username and password in the fields below.)
    362              
    363             a message provided on the first login attempt
    364              
    365             =item REMEMBERUSER_OPTION (default: 1)
    366              
    367             provide a checkbox to offer to remember the users name in a cookie so that
    368             their user name will be pre-filled the next time they log in
    369              
    370             =item REMEMBERUSER_LABEL (default: Remember User Name)
    371              
    372             the label for the remember user name checkbox
    373              
    374             =item REMEMBERUSER_COOKIENAME (default: CAPAUTHTOKEN)
    375              
    376             the name of the cookie where the user name will be saved
    377              
    378             =item REGISTER_URL (default: )
    379              
    380             the URL for the register new account link
    381              
    382             =item REGISTER_LABEL (default: Register Now!)
    383              
    384             the label for the register new account link
    385              
    386             =item FORGOTPASSWORD_URL (default: )
    387              
    388             the URL for the forgot password link
    389              
    390             =item FORGOTPASSWORD_LABEL (default: Forgot Password?)
    391              
    392             the label for the forgot password link
    393              
    394             =item INVALIDPASSWORD_MESSAGE (default: Invalid username or password
    (login attempt %d)
    395              
    396             a message given when a login failed
    397              
    398             =item INCLUDE_STYLESHEET (default: 1)
    399              
    400             use this to disable the built in style-sheet for the login box so you can provide your own custom styles
    401              
    402             =item FORM_SUBMIT_METHOD (default: post)
    403              
    404             use this to get the form to submit using 'get' instead of 'post'
    405              
    406             =item FOCUS_FORM_ONLOAD (default: 1)
    407              
    408             use this to automatically focus the login form when the page loads so a user can start typing right away.
    409              
    410             =item BASE_COLOUR (default: #445588)
    411              
    412             This is the base colour that will be used in the included login box. All other
    413             colours are automatically calculated based on this colour (unless you hardcode
    414             the colour values). In order to calculate other colours, you will need the
    415             Color::Calc module. If you do not have the Color::Calc module, then you will
    416             need to use fixed values for all of the colour options. All colour values
    417             besides the BASE_COLOUR can be simple percentage values (including the % sign).
    418             For example if you set the LIGHTER_COLOUR option to 80%, then the calculated
    419             colour will be 80% lighter than the BASE_COLOUR.
    420              
    421             =item LIGHT_COLOUR (default: 50% or #a2aac4)
    422              
    423             A colour that is lighter than the base colour.
    424              
    425             =item LIGHTER_COLOUR (default: 75% or #d0d5e1)
    426              
    427             A colour that is another step lighter than the light colour.
    428              
    429             =item DARK_COLOUR (default: 30% or #303c5f)
    430              
    431             A colour that is darker than the base colour.
    432              
    433             =item DARKER_COLOUR (default: 60% or #1b2236)
    434              
    435             A colour that is another step darker than the dark colour.
    436              
    437             =item GREY_COLOUR (default: #565656)
    438              
    439             A grey colour that is calculated by desaturating the base colour.
    440              
    441              
    442             =back
    443              
    444             LOGIN_FORM => {
    445             TITLE => 'Login',
    446             SUBMIT_LABEL => 'Login',
    447             REMEMBERUSER_LABEL => 1,
    448             BASE_COLOUR => '#0099FF',
    449             LIGHTER_COLOUR => '#AAFFFF',
    450             DARK_COLOUR => '50%',
    451             }
    452              
    453             =head1 BUGS
    454              
    455             This is alpha software and as such, the features and interface
    456             are subject to change. So please check the Changes file when upgrading.
    457              
    458             =head1 SEE ALSO
    459              
    460             L, perl(1)
    461              
    462             =head1 AUTHOR
    463              
    464             Author: Cees Hek ; Co-maintainer: Nicholas Bamber .
    465              
    466             =head1 CREDITS
    467              
    468             Thanks to SiteSuite (http://www.sitesuite.com.au) for funding the
    469             development of this plugin and for releasing it to the world.
    470              
    471             Thanks to Christian Walde for suggesting changes to fix the incompatibility with
    472             L and for help with github.
    473              
    474             =head1 LICENCE AND COPYRIGHT
    475              
    476             Copyright (c) 2005, SiteSuite. All rights reserved.
    477             Copyright (c) 2010, Nicholas Bamber. All rights reserved.
    478              
    479             This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
    480              
    481             =head1 DISCLAIMER OF WARRANTY
    482              
    483             BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR CORRECTION.
    484              
    485             IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
    486              
    487             =cut
    488              
    489             1;