App-Dochazka-REST

 view release on metacpan or  search on metacpan

lib/App/Dochazka/REST/Auth.pm  view on Meta::CPAN

sub _validate_session {
    my ( $self ) = @_;
    $log->debug( "Entering " . __PACKAGE__ . "::_validate_session" );

    my $r = $self->request;

    my $remote_addr = $r->{'env'}->{'REMOTE_ADDR'};

    my $session = $r->{'env'}->{'psgix.session'};
    $log->debug( "Session is " . Dumper( $session ) );

    return 0 unless %$session;
    return 0 unless _is_fresh( $session->{'last_seen'} );
    return 0 unless $session->{'ip_addr'} eq $remote_addr;
    return 0 unless exists( $session->{'eid'} ) and $session->{'eid'};

    $log->info( "Detected valid existing session" .
        ", EID " . $session->{'eid'} .
        ", last seen " .  $session->{'last_seen'}
    );

    $session->{'last_seen'} = time;

    my $emp = App::Dochazka::REST::Model::Employee->load_by_eid( $dbix_conn, $session->{'eid'} )->payload;
    die "missing employee object in session management"
        unless $emp->isa( "App::Dochazka::REST::Model::Employee" );
    $self->push_onto_context( {
        current => $emp->TO_JSON,
        current_obj => $emp,
        current_priv => $emp->priv( $dbix_conn ),
        dbix_conn => $dbix_conn,
    } );

    return 1;
}


=head3 _is_fresh

Takes a single argument, which is assumed to be number of seconds since
epoch when the session was last seen. This is compared to "now" and if the
difference is greater than the DOCHAZKA_REST_SESSION_EXPIRATION_TIME site
parameter, the return value is false, otherwise true.

=cut

sub _is_fresh {
    $log->debug( "Entering " . __PACKAGE__ . "::_is_fresh" );
    my ( $last_seen ) = validate_pos( @_, { type => SCALAR } );
    if ( time - $last_seen > $site->DOCHAZKA_REST_SESSION_EXPIRATION_TIME ) {
        $log->error( "Session expired!" );
        return 0;
    }
    return 1;
}


=head3 _authenticate

Authenticate the nick associated with an incoming REST request.  Takes a nick
and a password (i.e., a set of credentials). Returns a status object, which
will have level 'OK' on success (with employee object in the payload), 'NOT_OK'
on failure. In the latter case, there will be a declared status.

=cut

sub _authenticate {
    my ( $self, $nick, $password ) = @_;
    my ( $status, $emp );
    $log->debug( "Entering " . __PACKAGE__ . "::_authenticate" );

    # empty credentials: fall back to demo/demo
    if ( $nick ) {
        $log->notice( "Login attempt from $nick" );
    } else {
        $log->notice( "Login attempt from (anonymous) -- defaulting to demo/demo" );
        $nick = 'demo'; 
        $password = 'demo'; 
    }

    $log->debug( "\$site->DOCHAZKA_LDAP is " . $site->DOCHAZKA_LDAP );

    # check if LDAP is enabled and if the employee exists in LDAP
    if ( ! $meta->META_DOCHAZKA_UNIT_TESTING and 
         $site->DOCHAZKA_LDAP and
         ldap_exists( $nick ) 
    ) {

        $log->info( "Detected authentication attempt from $nick, a known LDAP user" );
        #$log->debug( "Password provided: $password" );

        # - authenticate by LDAP bind
        if ( ldap_auth( $nick, $password ) ) {
            # successful LDAP auth: if the employee doesn't already exist in
            # the database, possibly autocreate
            $status = autocreate_employee( $dbix_conn, $nick );
            return $status unless $status->ok;
        } else {
            return $CELL->status_not_ok( 'DOCHAZKA_EMPLOYEE_AUTH' );
        }

        # load the employee object
        my $emp = App::Dochazka::REST::Model::Employee->load_by_nick( $dbix_conn, $nick )->payload;
        die "missing employee object in _authenticate" unless ref($emp) eq "App::Dochazka::REST::Model::Employee";
        return $CELL->status_ok( 'DOCHAZKA_EMPLOYEE_AUTH', payload => $emp );
    }

    # if not, authenticate against the password stored in the employee object.
    else {

        $log->notice( "Employee $nick not found in LDAP; reverting to internal auth" );

        # - check if this employee exists in database
        my $emp = nick_exists( $dbix_conn, $nick );

        if ( ! defined( $emp ) or ! $emp->isa( 'App::Dochazka::REST::Model::Employee' ) ) {
            $log->notice( "Rejecting login attempt from unknown user $nick" );
            $self->mrest_declare_status( explanation => "Authentication failed for user $nick", permanent => 1 );
            return $CELL->status_not_ok;
        }

        # - the password might be empty
        $password = '' unless defined( $password );
        my $passhash = $emp->passhash;
        $passhash = '' unless defined( $passhash );

        # - check password against passhash 
        my ( $ppr, $status );
        try {
            $ppr = Authen::Passphrase::SaltedDigest->new(
                algorithm => "SHA-512",
                salt_hex => $emp->salt,



( run in 0.936 second using v1.01-cache-2.11-cpan-39bf76dae61 )