Dancer-Plugin-Auth-Extensible

 view release on metacpan or  search on metacpan

lib/Dancer/Plugin/Auth/Extensible.pm  view on Meta::CPAN

# succeeded and the response.
# Note: all provider class methods return a single value; if any need to return
# a list in future, this will need changing)
sub _try_realms {
    my ($method, @args);
    for my $realm (keys %{ $settings->{realms} }) {
        my $provider = auth_provider($realm);
        if (!$provider->can($method)) {
            die "Provider $provider does not provide a $method method!";
        }
        if (defined(my $result = $provider->$method(@args))) {
            return $result;
        }
    }
    return;
}

# Set up routes to serve default pages, if desired
if ( !$settings->{no_default_pages} ) {
    get $loginpage => sub {
        if(logged_in_user()) {
            redirect params->{return_url} || $userhomepage;
        }

        status 401;
        my $_default_login_page =
          $settings->{login_page_handler} || '_default_login_page';
        no strict 'refs';
        return &{$_default_login_page}();
    };
    get $deniedpage => sub {
        status 403;
        my $_default_permission_denied_page =
          $settings->{permission_denied_page_handler}
          || '_default_permission_denied_page';
        no strict 'refs';
        return &{$_default_permission_denied_page}();
    };
}


# If no_login_handler is set, let the user do the login/logout herself
if (!$settings->{no_login_handler}) {

# Handle logging in...
post $loginpage => sub {
    # For security, ensure the username and password are straight scalars; if
    # the app is using a serializer and we were sent a blob of JSON, they could
    # have come from that JSON, and thus could be hashrefs (JSON SQL injection)
    # - for database providers, feeding a carefully crafted hashref to the SQL
    # builder could result in different SQL to what we'd expect.
    # For instance, if we pass password => params->{password} to an SQL builder,
    # we'd expect the query to include e.g. "WHERE password = '...'" (likely
    # with paremeterisation) - but if params->{password} was something
    # different, e.g. { 'like' => '%' }, we might end up with some SQL like
    # WHERE password LIKE '%' instead - which would not be a Good Thing.
    my ($username, $password) = @{ params() }{qw(username password)};
    for ($username, $password) {
        if (ref $_) {
            # TODO: handle more cleanly
            die "Attempt to pass a reference as username/password blocked";
        }
    }

    if(logged_in_user()) {
        redirect params->{return_url} || $userhomepage;
    }

    my ($success, $realm) = authenticate_user(
        $username, $password
    );
    if ($success) {
        session logged_in_user => $username;
        session logged_in_user_realm => $realm;
        redirect params->{return_url} || $userhomepage;
    } else {
        vars->{login_failed}++;
        forward $loginpage, { login_failed => 1 }, { method => 'GET' };
    }
};

# ... and logging out.
any ['get','post'] => $logoutpage => sub {
    session->destroy;
    if (params->{return_url}) {
        redirect params->{return_url};
    } elsif ($exitpage) {
        redirect $exitpage;
    } else {
        # TODO: perhaps make this more configurable, perhaps by attempting to
        # render a template first.
        return "OK, logged out successfully.";
    }
};

}


sub _default_permission_denied_page {
    return <<PAGE
<h1>Permission Denied</h1>

<p>
Sorry, you're not allowed to access that page.
</p>
PAGE
}

sub _default_login_page {
    my $login_fail_message = vars->{login_failed}
        ? "<p>LOGIN FAILED</p>"
        : "";
    my $return_url = params->{return_url} || '';
    return <<PAGE;
<h1>Login Required</h1>

<p>
You need to log in to continue.
</p>

$login_fail_message



( run in 2.007 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )