package HaCi::Authentication::ldap;

use strict;
use HaCi::Log qw/warnl debug/;
use HaCi::GUI::gettext qw/_gettext/;
use Net::LDAP;
use Data::Dumper;

require Exporter;
our @ISA        = qw(Exporter);

our $conf; *conf  = \$HaCi::Conf::conf;

sub new {
	my $class	= shift;
	my $self	= {};

	bless $self, $class;
	return $self;
}

sub user {
	my $self	= shift;
	my $user	= shift;

	if (defined $user) {
		$self->{user}	= $user;
	} else {
		return $self->{user};
	}
}

sub pass {
	my $self	= shift;
	my $pass	= shift;

	if (defined $pass) {
		$self->{pass}	= $pass;
	} else {
		return $self->{pass};
	}
}

sub session {
	my $self	= shift;
	my $sess	= shift;

	if (defined $sess) {
		$self->{sess}	= $sess;
	} else {
		return $self->{sess};
	}
}

sub authenticate {
	my $self	= shift;
	my $user	= $self->user();

	$self->{sess}->param('authenticated', 0);

	my $ldap	= undef;
	my $host	= $conf->{user}->{auth}->{authparams}->{ldap}->{host} || ['localhost'];

	my $bOK	= 0;
	foreach (@{$host}) {
		my $host	= $_;
		unless ($ldap = Net::LDAP->new($host)) {
			my $error	= "Authentication failed: Cannot connect to LDAP Server '$host': " . $@;
			$conf->{var}->{authenticationError} .= $error . '<br>';
			warn $error;
		} else {
			$bOK	= 1;
			last;
		}
	}
	return 0 unless $bOK;


	my $bindDN	= $conf->{user}->{auth}->{authparams}->{ldap}->{binddn} || '';
	my $bindPW	= $conf->{user}->{auth}->{authparams}->{ldap}->{bindpw} || '';
	my $baseDN	= $conf->{user}->{auth}->{authparams}->{ldap}->{basedn} || '';
	my $filter	= $conf->{user}->{auth}->{authparams}->{ldap}->{filter} || '';
	if ($filter) {
		unless ($bindPW) {
			$conf->{var}->{authenticationError} = "Authentication failed: No passsword configured for binding";
			return 0;
		}

		my $msg	= $ldap->bind($bindDN, password => $bindPW);
		if ($msg->code()) {
			$conf->{var}->{authenticationError} = "Authentication failed: Cannot bind to LDAP server";
			return 0;
		}

		$filter		=~ s/<USER>/$user/g;
		my $search	= $ldap->search(
			base	=> $baseDN,
			filter	=> $filter,
			scope	=> 'sub',
			attrs	=> ['cn']
		);
		my @results	= $search->entries;
		if ($#results < 0) {
			$conf->{var}->{authenticationError} = "Authentication failed: User not known";
			return 0;
		}
		$bindDN	= $results[0]->dn();

	} else {
		$bindDN		=~ s/<USER>/$user/g;
	}

	&HaCi::Utils::debug("Authenticate [ldap] with: $bindDN\n");

	my $login	= $ldap->bind ($bindDN, password => $self->pass());
	if ($login->code) {
		&HaCi::Utils::debug("Authentication Failed: " . $login->error() . "\n");
		$conf->{var}->{authenticationError} = _gettext("Authentication failed!");
	} else {
		$self->{sess}->param('authenticated', 1);
		$self->{sess}->param('username', $self->user());
		&HaCi::Utils::debug("Sucessfully logged in!");
	}
	
	return &isAutenticated($self);
}

sub isAutenticated {
	my $self	= shift;

	my $username	= $self->{sess}->param('username') || $self->user();
	
	if ($username) {
		my $userTable	= $conf->{var}->{TABLES}->{user};
		unless (defined $userTable) {
			warn "Cannot authenticate! DB Error (user)\n";
			return 0;
		}
		
		my $user	= ($userTable->search(['ID'], {'%CS%' => 1, username => $username}))[0];
	
		if (!defined $user || !exists $user->{ID}) {
			&debug("Authentication failed: User '$username' not in Database!");
			$conf->{var}->{authenticationError} = _gettext("Authentication failed!");
			$self->{sess}->clear('authenticated');
			$self->{sess}->param('authenticated', 0);
			return 0;
		}
	}

	return (defined $self->{sess}->param('authenticated')) ? $self->{sess}->param('authenticated') : 0;
}

1;
