Authen-Simple-WebForm

 view release on metacpan or  search on metacpan

lib/Authen/Simple/WebForm.pm  view on Meta::CPAN

String or a compiled regex (eg. C<qr/please\s+login/i>).

If you want to make sure the page you got is the login form, you can set
a string here to check for. The page content will be tested against this,
and authentication will fail (with a logged error) if this doesn't match.

With this, you can make sure the server isn't returning a sorry server page, or similar.

Off by default.


=item initial_expect_cookie

String or a compiled regex (eg. C<qr/please\s+login/i>).

Similar to initial_expect, but checks the cookies returned by the page.

NOTE: this matches the cookie key, and the value must simple have some length.

Off by default.


=item check_initial_status_code

Boolean, set to 0 to disable.

Set to undef to skip checking the response status code from the initial page. Otherwise, it must match HTTP::Status->is_success.

Defaults to enabled (1).


=item initial_request_method

This can be either "GET" or "POST".

How the initial url will be sent to the server, either via HTTP GET request, or HTTP POST.

Defaults to "GET".


=item login_url

REQUIRED

The URL to which the login credentials will be submitted.

For example: https://host.company.com/login.pl


=item login_expect

String or a compiled regex (eg. C<qr/login\s+successful/i>).

Set to a unique string to expect in the resulting page when the login was successful.

Be default, this is not turned on. If you do not set this, then as long as the
server returns a successful status code (see HTTP::Status::is_success), then
the user will be authenticated. Most form based login systems return a successful
status code even when the login fails, so you'll probably want to set this.

A notable exception is the use of something like L<Apache::AuthCookie>, which
will return a 403 Forbidden error code when authentication fails.

Off by default.


=item login_expect_cookie

String or a compiled regex (eg. C<qr/please\s+login/i>).

Similar to login_expect, but checks the cookies returned by the page. If you are also using "initial_url", please be aware that an cookies set by that page will also test true here (ie. this checks our cookie jar, not the content of the page). The co...

NOTE: this matches the cookie key, and the value must simple have some length.

Off by default.


=item check_login_status_code

Boolean, set to 0 to disable.

Set to undef to skip checking the response status code from the login page. Otherwise, it must match HTTP::Status->is_success.

Defaults to enabled (1).


=item login_request_method

This can be either "GET" or "POST".

How the initial url will be sent to the server, either via HTTP GET request, or HTTP POST.

Defaults to "POST".


=item username_prefix

Username prefix string.

With this, you can automatically prefix your the submitted username with
some string. This can can be useful if loging into a windows domain, for
example. In that case, you would set it to something like "MyDomain\".

Off be default.


=item username_field

Form field name for the username.

Defaults to "username".


=item password_field

Form field name for the password.

Defaults to "password".


=item extra_fields

lib/Authen/Simple/WebForm.pm  view on Meta::CPAN

    }

    # get an inital page?
    if ($self->initial_url)
    {
        my $res = ($initial_req_method eq 'GET') ? $ua->get($self->initial_url, @headers):
                                                   $ua->post($self->initial_url, @headers);
        if ($self->trace)
        {
            print STDERR ("-"x80)."\n";
            print STDERR "TRACE: initial response, response code [".$res->code."]\n";
            print STDERR "TRACE: initial response, cookies [".$ua->cookie_jar->as_string()."]\n";
            print STDERR $res->decoded_content;
            print STDERR "\n\n\n";
            print STDERR ("-"x80)."\n";
        }
        # make sure status code is ok?
        if ($self->check_initial_status_code)
        {
            unless ($res->is_success)
            {
                $self->log->error("Can't get ".$self->initial_url." -- ".$res->status_line)
                    if $self->log;
                return 0;
            }
        }

        # do we care to check the content?
        if ($self->initial_expect)
        {
            my $expect = $self->initial_expect;
            unless (ref($expect) eq 'Regexp') {
                $expect = qr/\Q$expect\E/;
            }
            unless ($res->decoded_content =~ /$expect/)
            {
                $self->log->error("Initial url didn't return expected results.") if $self->log;
                return 0;
            }
        }

        # do we care to check for a cookie
        if ($self->initial_expect_cookie)
        {
            my $expect = $self->initial_expect_cookie;

            my $found = 0;
            my $search; # cookie_jar search callback

            if (ref($expect) eq 'Regexp')
            {
                $search = sub { $found++ if $_[1] =~ /$expect/ && length($_[2]); };
            } else {
                $search = sub { $found++ if $_[1] eq $expect && length($_[2]); };
            }

            # search the cookie jar
            $ua->cookie_jar->scan($search);
            unless ($found)
            {
                $self->log->debug("Failed to authenticate user '$full_username'. Reason: Initial Cookie $expect was not found.")
                    if $self->log;
                return 0;
            }
        }
    }


    # build data to post
    my @data = (
        $self->username_field   => $full_username,
        $self->password_field   => $password
        );
    # add an extra fields to submit
    my $extra_fields = $self->extra_fields;
    if (ref($extra_fields) eq 'ARRAY' && @$extra_fields)
    {
        if ((@$extra_fields % 2) == 0)
        {
            push(@data, @$extra_fields);
        } else {
            $self->log->error("Invalid extra_fields option.") if $self->log;
            return 0;
        }
    }

    # attempt to login
    my $res;
    if ($login_req_method eq 'GET')
    {
        my $url = URI->new($self->login_url);
        unless ($url) {
            $self->log->error("Unable to parse login_url. $@") if $self->log;
            return 0;
        }
        $url->query_form( \@data );
        $res = $ua->get($url, @headers);
    } else { # POST
        $res = $ua->post($self->login_url, \@data, @headers);
    }
    if ($self->trace)
    {
        print STDERR ("-"x80)."\n";
        print STDERR "TRACE: initial response, response code [".$res->code."]\n";
        print STDERR "TRACE: initial response, cookies [".$ua->cookie_jar->as_string()."]\n";
        print STDERR $res->decoded_content;
        print STDERR "\n\n\n";
        print STDERR ("-"x80)."\n";
    }

    # make sure status code is ok?
    if ($self->check_login_status_code)
    {
        unless ($res->is_success)
        {
            if ($res->is_redirect)
            {
                $self->log->debug("Failed to authenticate user '$full_username'. Reason: Login page returned redirect status code '".$res->code."'. You may wish to enable lwp_requests_redirectable -- ".$res->status_line)
                    if $self->log;
            } else {
                $self->log->debug("Failed to authenticate user '$full_username'. Reason: Login page returned invalid status code '".$res->code."' -- ".$res->status_line)
                    if $self->log;
            }
            return 0;
        }
    }

    # do we care to check the content?
    if ($self->login_expect)
    {
        my $expect = $self->login_expect;
        unless (ref($expect) eq 'Regexp') {
            $expect = qr/\Q$expect\E/;
        }
        unless ($res->decoded_content =~ /$expect/)
        {
            $self->log->debug("Failed to authenticate user '$full_username'. Reason: Login page response did not match expected value.")
                if $self->log;
            return 0;
        }
    }

    # do we care to check for a cookie
    if ($self->login_expect_cookie)
    {
        my $expect = $self->login_expect_cookie;

        my $found = 0;
        my $search; # cookie_jar search callback

        if (ref($expect) eq 'Regexp')
        {
            $search = sub { $found++ if $_[1] =~ /$expect/ && length($_[2]); };
        } else {
            $search = sub { $found++ if $_[1] eq $expect && length($_[2]); };
        }

        # search the cookie jar
        $ua->cookie_jar->scan($search);
        unless ($found)
        {
            $self->log->debug("Failed to authenticate user '$full_username'. Reason: Login Cookie $expect was not found.")
                if $self->log;
            return 0;
        }
    }

    $self->log->debug("Successfully authenticated user '$full_username'.") if $self->log;
    return 1;
}

=head1 TODO

Add lwp_cookie_jar option(s) so that it may use a file.

Add a debug mode. It's often difficult to determine what content is being returned, and what to look for. The debug mode should print each step out to STDERR, and include the relevant response information from the page.

Write tests using HTTP::Daemon as a local webserver. See LWP test t/local/http.t and t/local/chunked.t for example.

=head1 AUTHOR

Joshua I. Miller, C<< <unrtst at cpan.org> >>

=head1 BUGS

Please report any bugs or feature requests to C<bug-authen-simple-webform at rt.cpan.org>, or through
the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Authen-Simple-WebForm>.  I will be notified, and then you'll
automatically be notified of progress on your bug as I make changes.




=head1 SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc Authen::Simple::WebForm


You can also look for information at:

=over 4

=item * RT: CPAN's request tracker

L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Authen-Simple-WebForm>

=item * AnnoCPAN: Annotated CPAN documentation

L<http://annocpan.org/dist/Authen-Simple-WebForm>

=item * CPAN Ratings

L<http://cpanratings.perl.org/d/Authen-Simple-WebForm>

=item * Search CPAN

L<http://search.cpan.org/dist/Authen-Simple-WebForm>

=back




( run in 1.860 second using v1.01-cache-2.11-cpan-d7f47b0818f )