aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/FPanel/Interface.pm118
-rw-r--r--lib/FPanel/Login.pm194
2 files changed, 312 insertions, 0 deletions
diff --git a/lib/FPanel/Interface.pm b/lib/FPanel/Interface.pm
new file mode 100644
index 0000000..adac0f0
--- /dev/null
+++ b/lib/FPanel/Interface.pm
@@ -0,0 +1,118 @@
+package FPanel::Interface;
+
+use strict;
+use warnings;
+use utf8;
+
+use lib 'lib';
+use base 'FPanel::Login';
+
+sub cgiapp_init {
+ my $self = shift;
+
+ $self->SUPER::cgiapp_init;
+
+ # define runmodes (pages) that require successful login:
+ $self->authen->protected_runmodes( ':all' );
+}
+
+sub index : Runmode {
+ my $self = shift;
+ my $template = $self->load_tmpl("index.html");
+ my $domain = (split /\//, $ENV{PATH_INFO},3)[1];
+ $template->param({
+ NAME => 'INDEX',
+ URL => $self->query->url(),
+ MYDOMAIN => $domain,
+ USER => $self->authen->username,
+ });
+ return $template->output;
+}
+
+sub DomainList : StartRunmode {
+ my $self = shift;
+
+ my ($u,$d) = split /@/, $self->authen->username, 2;
+ my $dn = "fvu=$u,fvd=$d,ou=virtual,o=mailHosting,dc=fripost,dc=dev";
+
+ my $ldap = Net::LDAP->new( 'ldap://127.0.0.1:389',
+ , async => 1,
+ , onerror => 'die'
+ );
+ my $sasl = Authen::SASL->new( mechanism => 'DIGEST-MD5'
+ , callback => { user => 'FPanel'
+ , pass => 'panel'
+ , authname => "dn:$dn" }
+ );
+ my $mesg = $ldap->bind( sasl => $sasl ) ;
+ die $mesg->error if $mesg->code;
+
+ my $domains = $ldap->search( base => "ou=virtual,o=mailHosting,dc=fripost,dc=dev"
+ , scope => 'one'
+ , filter => 'objectClass=FripostVirtualDomain'
+ , deref => 'never'
+ );
+ die $domains->error if $domains->code;
+
+
+ my $template = $self->load_tmpl("domain-list.html");
+ my $url = $self->query->url();
+ $template->param( URL => $url );
+ $template->param( USER_LOCALPART => $u, USER_DOMAINPART => $d);
+ my $i = 1;
+ $template->param( DOMAIN => [
+ map { $i = 1-$i;
+ { DOMAIN => $_->get_value('fvd')
+ , PERMS => &list_perms($_, $dn)
+ , DESCRIPTION => join ("\n", $_->get_value('description'))
+ , ISACTIVE => $_->get_value('fripostIsStatusActive') eq 'TRUE' ? 1 : 0
+ , URL => $url
+ , ODD => $i
+ };
+ }
+ $domains->sorted('fvd')
+ ]);
+ return $template->output;
+}
+
+sub list_perms {
+ my ($entry, $dn) = @_;
+ my $perms = '';
+
+ my $canCreateAlias = $entry->get_value ('fripostCanCreateAlias', asref => 1);
+ $perms .= 'a'
+ if defined $canCreateAlias and
+ grep { $dn eq $_ or (split /,/,$dn,2)[1] eq $_ }
+ @{$canCreateAlias};
+
+ my $canCreateList = $entry->get_value ('fripostCanCreateList', asref => 1);
+ $perms .= 'l'
+ if defined $canCreateList and
+ grep { $dn eq $_ or (split /,/,$dn,2)[1] eq $_ }
+ @{$canCreateList};
+
+ my $owner = $entry->get_value ('fripostOwner', asref => 1);
+ $perms = 'o'
+ if defined $owner and grep { $dn eq $_ } @{$owner};
+
+ my $postmaster = $entry->get_value ('fripostPostmaster', asref => 1);
+ $perms = 'p'
+ if defined $postmaster and grep { $dn eq $_ } @{$postmaster};
+
+ if ( $perms =~ /a/) {
+ return 'can create aliases & lists' if ( $perms =~ /l/);
+ return 'can create aliases';
+ }
+ elsif ( $perms eq 'l' ) {
+ return 'can create lists';
+ }
+ elsif ( $perms eq 'o' ) {
+ return 'owner';
+ }
+ elsif ( $perms eq 'p' ) {
+ return 'postmaster';
+ }
+}
+
+1;
+
diff --git a/lib/FPanel/Login.pm b/lib/FPanel/Login.pm
new file mode 100644
index 0000000..8f0af21
--- /dev/null
+++ b/lib/FPanel/Login.pm
@@ -0,0 +1,194 @@
+package FPanel::Login;
+
+use strict;
+use warnings;
+use utf8;
+
+use base 'CGI::Application';
+
+use CGI::Application::Plugin::AutoRunmode;
+use CGI::Application::Plugin::Session;
+use CGI::Application::Plugin::Authentication;
+use CGI::Application::Plugin::Redirect;
+use CGI::Application::Plugin::ConfigAuto qw/cfg/;
+
+use Net::LDAP;
+use Authen::SASL;
+
+
+# This method is called right before the 'setup' method below. It
+# initializes the session and authentication configurations.
+sub cgiapp_init {
+ my $self = shift;
+
+ $self->session_config(
+ # TODO: Use a Berkeley DB instead
+ CGI_SESSION_OPTIONS => [ 'driver:File'
+ , $self->query
+ , { Directory => '/tmp/fpanel-cgisess' }
+ ],
+ DEFAULT_EXPIRY => '+24h',
+ COOKIE_PARAMS => { -path => '/index.cgi/'
+ , -httponly => 1
+# # TODO: Turn the secure flag for HTTPS connections
+ , -secure => 0
+ },
+ SEND_COOKIE => 1,
+ );
+
+ # Configure authentication parameters
+ $self->authen->config(
+ DRIVER => [ 'Generic'
+ , \&authenticate ],
+ STORE => 'Session',
+ LOGOUT_RUNMODE => 'logout',
+ LOGIN_RUNMODE => 'login',
+ RENDER_LOGIN => \&login_box,
+ LOGIN_SESSION_TIMEOUT => { IDLE_FOR => '30m' },
+ );
+
+ # The run modes that require authentication
+ $self->authen->protected_runmodes( qw /okay error_rm/ );
+}
+
+
+# This method is called by the inherited new() constructor method.
+sub setup {
+ my $self = shift;
+
+ $self->tmpl_path( 'template/' );
+ $self->mode_param( \&mymode_param );
+}
+
+
+# This method choses the Run Mode depending on the URL and query string.
+sub mymode_param {
+ my $self = shift;
+ my $q = $self->query;
+ my @path = split /\//, $ENV{PATH_INFO};
+ pop @path if $#path > 0 and $path[$#path] eq '';
+
+ my $mode = 'DomainList';
+
+ if (defined $q->param('authen_username') and
+ defined $q->param('authen_password')) {
+ $mode = 'okay'
+ }
+ elsif (defined $q->param('a')) {
+ my $a = $q->param('a');
+ if ($a eq 'login') {
+ $mode = 'login';
+ }
+ elsif ($a eq 'logout') {
+ $mode = 'logout';
+ }
+ elsif ($a eq 'AddDomain') {
+ $mode = 'AddDomain';
+ }
+ }
+ elsif ($#path < 0) {
+ $mode = 'DomainList';
+ }
+ elsif ($path[1] ne '') {
+ # $domain = $path[1];
+ $mode = 'index';
+ }
+ print STDERR $ENV{PATH_INFO} . '?' . $q->query_string
+ . " -> "
+ . $mode
+ . "\n";
+ return $mode;
+}
+
+
+sub okay : Runmode {
+ my $self = shift;
+ my $destination = $self->query->param('destination') //
+ $self->query->url;
+ return $self->redirect($destination);
+}
+
+sub login : Runmode {
+ my $self = shift;
+ my $url = $self->query->url;
+
+ # Do not come back here afterwards
+ $self->query->delete( 'a' )
+ if (defined $self->query->param('a')) and
+ $self->query->param('a') eq 'login';
+
+ # A logged user has no reason to ask for a relogin
+ $self->authen->logout() if defined $self->authen->username;
+
+ $self->query->param( destination => $self->query->self_url)
+ unless (defined $self->query->param('destination'));
+
+ return $self->login_box;
+}
+
+sub login_box {
+ my $self = shift;
+
+ my $template = $self->load_tmpl('login.html');
+
+ my $destination = $self->query->param('destination') //
+ $self->mymode_param();
+
+ $template->param(ERROR => $self->authen->login_attempts);
+ $template->param(DESTINATION => $destination);
+
+ return $template->output;
+}
+
+sub logout : Runmode {
+ my $self = shift;
+
+ if ($self->authen->username) {
+ $self->authen->logout;
+ $self->session->delete;
+ }
+ return $self->redirect($self->query->url . '/');
+}
+
+sub error_rm : ErrorRunmode {
+ my $self = shift;
+ my $error = shift;
+ my $template = $self->load_tmpl("template/error.html");
+ $template->param(NAME => 'ERROR');
+ $template->param(MESSAGE => $error);
+ $template->param(URL => $self->query->url);
+ return $template->output;
+}
+
+#sub AUTOLOAD : Runmode {
+# my $self = shift;
+# my $rm = shift;
+# my $template = $self->load_tmpl("template/error.html");
+# $template->param(NAME => 'AUTOLOAD');
+# $template->param(MESSAGE =>
+# "Error: could not find run mode \'$rm\'\n");
+# $template->param(URL => $self->query->url);
+# return $template->output;
+#}
+
+sub authenticate {
+# my $self = shift;
+
+ my ($u, $p) = @_;
+ my ($l,$d) = split /@/, $u, 2;
+
+
+# my %CFG = $self->cfg;
+
+ unless (defined $d) {
+ $d = 'fripost.org';
+ $u .= '@'.$d;
+ }
+ my $ldap = Net::LDAP->new( 'ldap://127.0.0.1:389' );
+ my $mesg = $ldap->bind ( "fvu=$l,fvd=$d,ou=virtual,o=mailHosting,dc=fripost,dc=dev"
+ , password => $p );
+ $mesg->code ? 0 : $u;
+}
+
+1;
+