diff --git a/Makefile b/Makefile index 387d13dec..96fef7be1 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,12 @@ RLMPREFIX=$(DESTDIR)/$(LMPREFIX) # BIN dirs BINDIR=$(LMPREFIX)/bin RBINDIR=$(DESTDIR)/$(BINDIR) +SBINDIR=$(LMPREFIX)/sbin +RSBINDIR=$(DESTDIR)/$(SBINDIR) +INITDIR=$(LMPREFIX)/etc/init.d +RINITDIR=$(DESTDIR)/$(INITDIR) +ETCDEFAULTDIR=$(LMPREFIX)/etc/default +RETCDEFAULTDIR=$(DESTDIR)/$(ETCDEFAULTDIR) DATADIR=$(LMPREFIX)/data RDATADIR=$(DESTDIR)/$(DATADIR) @@ -104,6 +110,8 @@ RCAPTCHADIR=$(DESTDIR)/$(CAPTCHADIR) # Apache user/group APACHEUSER= APACHEGROUP= +FASTCGIUSER=$(APACHEUSER) +FASTCGIGROUP=$(APACHEGROUP) # Apache version APACHEVERSION=2.X @@ -189,20 +197,22 @@ all: configure common handler manager portal @echo @echo 'Other targets launched by "make install" :' @echo " * Perl libraries install :" - @echo " - install_libs (all Perl libraries)" + @echo " - install_libs (all Perl libraries)" @echo " - install_portal_libs" @echo " - install_manager_libs" @echo " - install_handler_libs" @echo " * Binaries install :" - @echo " - install_bin ($(BINDIR))" + @echo " - install_bin ($(BINDIR))" + @echo " * FastCGI server install (required for Nginx)" + @echo " - install_fastcgi_server ($(SBINDIR))" @echo " * Web sites install :" - @echo " - install_site (all sites including install_doc_site)" - @echo " - install_portal_site ($(PORTALDIR))" - @echo " - install_manager_site ($(MANAGERDIR))" - @echo " - install_handler_site ($(HANDLERDIR))" + @echo " - install_site (all sites including install_doc_site)" + @echo " - install_portal_site ($(PORTALDIR))" + @echo " - install_manager_site ($(MANAGERDIR))" + @echo " - install_handler_site ($(HANDLERDIR))" @echo " * Documentation install :" - @echo " - install_doc_site ($(DEFDOCDIR))" - @echo " - install_examples_site ($(EXAMPLESDIR))" + @echo " - install_doc_site ($(DEFDOCDIR))" + @echo " - install_examples_site ($(EXAMPLESDIR))" @echo @echo "Other languages documentation (fr only for now)" @echo " - fr-doc (needs OmegaT)" @@ -389,7 +399,7 @@ install: install_libs install_bin install_site # # Perl libraires install # -install_libs: common_install_libs install_handler_libs install_portal_libs install_manager_libs +install_libs: common_install_libs install_handler_libs install_portal_libs install_manager_libs install_fastcgi_server common_install_libs: common @$(MAKE) -C ${SRCCOMMONDIR} install @@ -435,6 +445,24 @@ install_bin: install_conf_dir fi @chmod +x $(RBINDIR)/* +install_fastcgi_server: + @install -v -d $(RSBINDIR) $(RINITDIR) $(RETCDEFAULTDIR) + @cp -f fastcgi-server/sbin/llng-fastcgi-server $(RSBINDIR) + @cp -f fastcgi-server/rc/llng-fastcgi-server $(RINITDIR) + @cp -f fastcgi-server/default/llng-fastcgi-server $(RETCDEFAULTDIR) + $(PERL) -pi -e 's#__SBINDIR__#$(SBINDIR)#;s#__DEFAULTDIR__#$(ETCDEFAULTDIR)#' \ + $(RETCDEFAULTDIR)/llng-fastcgi-server + @if [ ! "$(FASTCGIUSER)" ]; then \ + $(PERL) -pi -e 's#__USER__#nobody#' $(RETCDEFAULTDIR)/llng-fastcgi-server; \ + else \ + $(PERL) -pi -e 's#__USER__#$(FASTCGIUSER)#' $(RETCDEFAULTDIR)/llng-fastcgi-server; \ + fi + @if [ ! "$(FASTCGIGROUP)" ]; then \ + $(PERL) -pi -e 's#__USER__#nobody#' $(RETCDEFAULTDIR)/llng-fastcgi-server; \ + else \ + $(PERL) -pi -e 's#__USER__#$(FASTCGIGROUP)#' $(RETCDEFAULTDIR)/llng-fastcgi-server; \ + fi + # # SITE INSTALL # diff --git a/debian/control b/debian/control index 0bd45dca4..98fc494ae 100644 --- a/debian/control +++ b/debian/control @@ -107,11 +107,31 @@ Description: French documentation of Lemonldap::NG Web-SSO system . This package contains French html documentation. +package: lemonldap-ng-fastcgi-server +Architecture: all +Depends: ${misc:Depends}, + nginx-extras | nginx, + liblemonldap-ng-handler-perl, + libplack-perl +Suggests: nginx-extras +Description: Lemonldap::NG FastCGI server + Lemonldap::NG is a complete Web-SSO system that can run with reverse-proxies + or directly on application Apache servers. It can be used in conjunction with + OpenID-Connect, CAS and SAML systems as identity or service provider. It can + also be used as proxy between those federation systems. + . + It manages both authentication and authorization and provides headers for + accounting. So you can have a full AAA protection. Authorization are built by + associating a regular expression and a rule. Regular expression is applied on + the requested URL and the rule calculates if the user is authorized. + . + Lemonldap::NG FastCGI server provides a Nginx auth_request server. + Package: liblemonldap-ng-handler-perl Architecture: all Depends: ${misc:Depends}, ${perl:Depends}, - libapache2-mod-perl2 | nginx, + libapache2-mod-perl2 | lemonldap-ng-fastcgi-server, liblemonldap-ng-common-perl (= ${binary:Version}), libmouse-perl, liburi-perl, @@ -199,7 +219,7 @@ Depends: ${misc:Depends}, libwww-perl Recommends: lemonldap-ng-doc (= ${binary:Version}), libapache-session-browseable-perl, - libapache2-mod-fcgid | libapache2-mod-fastcgi | nginx, + libapache2-mod-fcgid | libapache2-mod-fastcgi | lemonldap-ng-fastcgi-server, libjson-xs-perl, liblwp-protocol-https-perl | libwww-perl (<< 6), libxml-libxml-perl, @@ -226,6 +246,7 @@ Package: liblemonldap-ng-portal-perl Architecture: all Depends: ${misc:Depends}, ${perl:Depends}, + httpd, libcgi-pm-perl, libclone-perl, libhtml-template-perl, diff --git a/debian/lemonldap-ng-fastcgi-server.default b/debian/lemonldap-ng-fastcgi-server.default new file mode 100644 index 000000000..b968fc797 --- /dev/null +++ b/debian/lemonldap-ng-fastcgi-server.default @@ -0,0 +1,15 @@ +# Number of process (default: 7) +#NPROC = 7 + +# Portal CGI path +#PORTAL_PATH = /var/lib/lemonldap-ng/portal + +# Unix socket to listen to +#SOCKET = /run/llng-fastcgi.sock + +# Pid file +#PID = /run/llng-fastcgi.pid + +# User and GROUP +USER = www-data +GROUP = www-data diff --git a/debian/lemonldap-ng-fastcgi-server.init b/debian/lemonldap-ng-fastcgi-server.init new file mode 100755 index 000000000..595c52c30 --- /dev/null +++ b/debian/lemonldap-ng-fastcgi-server.init @@ -0,0 +1,123 @@ +#!/bin/sh + +### BEGIN INIT INFO +# Provides: llng-fastcgi-server +# Required-Start: $local_fs $remote_fs $network $syslog $named +# Required-Stop: $local_fs $remote_fs $network $syslog $named +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: starts the Lemonldap::NG FastCGI server +# Description: starts Lemonldap::NG FastCGI server using start-stop-daemon +### END INIT INFO + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/sbin/llgn-fastcgi-server +NAME=llng-fastcgi-server +DESC=llng-fastcgi-server + +# Include llng-fastcgi-server defaults if available +if [ -r /etc/default/lemonldap-ng-fastcgi-server ]; then + . /etc/default/lemonldap-ng-fastcgi-server +fi + +STOP_SCHEDULE="${STOP_SCHEDULE:-QUIT/5/TERM/5/KILL/5}" + +test -x $DAEMON || exit 0 + +. /lib/init/vars.sh +. /lib/lsb/init-functions + +# Try to extract llng-fastcgi-server pidfile +if [ -z "$PID" ]; then + PID=/run/llng-fastcgi-server.pid +fi + +start_server() { + # Start the daemon/service + # + # Returns: + # 0 if daemon has been started + # 1 if daemon was already running + # 2 if daemon could not be started + start-stop-daemon --start --quiet --pidfile $PID --exec $DAEMON --test > /dev/null \ + || return 1 + start-stop-daemon --start --quiet --pidfile $PID --exec $DAEMON -- \ + $DAEMON_OPTS 2>/dev/null \ + || return 2 +} + +stop_server() { + # Stops the daemon/service + # + # Return + # 0 if daemon has been stopped + # 1 if daemon was already stopped + # 2 if daemon could not be stopped + # other if a failure occurred + start-stop-daemon --stop --quiet --retry=$STOP_SCHEDULE --pidfile $PID --name $NAME + RETVAL="$?" + sleep 1 + return "$RETVAL" +} + +reload_server() { + # Function that sends a SIGHUP to the daemon/service + start-stop-daemon --stop --signal HUP --quiet --pidfile $PID --name $NAME + return 0 +} + +case "$1" in + start) + log_daemon_msg "Starting $DESC" "$NAME" + start_server + case "$?" in + 0|1) log_end_msg 0 ;; + 2) log_end_msg 1 ;; + esac + ;; + stop) + log_daemon_msg "Stopping $DESC" "$NAME" + stop_server + case "$?" in + 0|1) log_end_msg 0 ;; + 2) log_end_msg 1 ;; + esac + ;; + restart) + log_daemon_msg "Restarting $DESC" "$NAME" + + # Check configuration before stopping llng-fastcgi-server + if ! test_config; then + log_end_msg 1 # Configuration error + exit $? + fi + + stop_server + case "$?" in + 0|1) + start_server + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + reload|force-reload) + log_daemon_msg "Reloading $DESC configuration" "$NAME" + reload_server + log_end_msg $? + ;; + status) + status_of_proc -p $PID "$DAEMON" "$NAME" && exit 0 || exit $? + ;; + *) + echo "Usage: $NAME {start|stop|restart|reload|force-reload|status}" >&2 + exit 3 + ;; +esac diff --git a/debian/lemonldap-ng-fastcgi-server.install b/debian/lemonldap-ng-fastcgi-server.install new file mode 100644 index 000000000..c1debe483 --- /dev/null +++ b/debian/lemonldap-ng-fastcgi-server.install @@ -0,0 +1 @@ +/usr/sbin/llng-fastcgi-server diff --git a/debian/lemonldap-ng-fastcgi-server.service b/debian/lemonldap-ng-fastcgi-server.service new file mode 100644 index 000000000..ca2fc559e --- /dev/null +++ b/debian/lemonldap-ng-fastcgi-server.service @@ -0,0 +1,14 @@ +[Unit] +Description=FastCGI server for Lemonldap::NG websso system + +[Service] +Type=forking +PIDFile=/run/llng-fasctcgi.pid +ExecStart=/usr/sbin/llng-fastcgi-server +ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/llng-fasctcgi.sock +TimeoutStop=2 +KillMode=mixed + +[Install] +WantedBy=multi-user.target + diff --git a/debian/rules b/debian/rules index 6a6595270..20f5a69c0 100755 --- a/debian/rules +++ b/debian/rules @@ -32,6 +32,7 @@ override_dh_auto_install: PREFIX=/usr/ \ LMPREFIX=/usr/share/lemonldap-ng/ \ BINDIR=$(LMSHAREDIR)/bin/ \ + SBINDIR=/usr/sbin \ DOCUMENTROOT=$(LMVARDIR) \ EXAMPLESDIR=/examples/ \ HANDLERDIR=$(LMVARDIR)/handler/ \ diff --git a/fastcgi-server/default/llng-fastcgi-server b/fastcgi-server/default/llng-fastcgi-server new file mode 100644 index 000000000..272dd5317 --- /dev/null +++ b/fastcgi-server/default/llng-fastcgi-server @@ -0,0 +1,15 @@ +# Number of process (default: 7) +#NPROC = 7 + +# Portal CGI path +#PORTAL_PATH = /var/lib/lemonldap-ng/portal + +# Unix socket to listen to +#SOCKET = /run/llng-fastcgi.sock + +# Pid file +#PID = /run/llng-fastcgi.pid + +# User and GROUP +USER = __USER__ +GROUP = __GROUP__ diff --git a/_example/rc/llng-fastcgi-server b/fastcgi-server/rc/llng-fastcgi-server similarity index 66% rename from _example/rc/llng-fastcgi-server rename to fastcgi-server/rc/llng-fastcgi-server index 7b955525a..e90e0c1ec 100755 --- a/_example/rc/llng-fastcgi-server +++ b/fastcgi-server/rc/llng-fastcgi-server @@ -1,34 +1,25 @@ #!/bin/sh ### BEGIN INIT INFO -# Provides: nginx +# Provides: llng-fastcgi-server # Required-Start: $local_fs $remote_fs $network $syslog $named # Required-Stop: $local_fs $remote_fs $network $syslog $named # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 -# Short-Description: starts the nginx web server -# Description: starts nginx using start-stop-daemon +# Short-Description: starts the Lemonldap::NG FastCGI server +# Description: starts Lemonldap::NG FastCGI server using start-stop-daemon ### END INIT INFO PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin -DAEMON=`which plackup` -APP=/usr/share/lemonldap-ng/fastcgi-server.psgi -PID=/run/llng-fastcgi-server.pid -NPROC=10 -MODE=deployment +DAEMON=__SBINDIR__/llgn-fastcgi-server NAME=llng-fastcgi-server DESC=llng-fastcgi-server -SOCKET=/run/llng-fastcgi-server.sock -USER=www-data -GROUP=www-data -# Include nginx defaults if available -if [ -r /etc/default/llng-fastcgi-server ]; then - . /etc/default/llng-fastcgi-server +# Include llng-fastcgi-server defaults if available +if [ -r __DEFAULTDIR__/llng-fastcgi-server ]; then + . __DEFAULTDIR__/llng-fastcgi-server fi -DAEMON_OPTS="-s FCGI --listen $SOCKET -a $APP --daemonize --pid $PID -nproc NPROC --proc-title llng-fastcgi-server --no-default-middleware -E $MODE" - STOP_SCHEDULE="${STOP_SCHEDULE:-QUIT/5/TERM/5/KILL/5}" test -x $DAEMON || exit 0 @@ -36,7 +27,7 @@ test -x $DAEMON || exit 0 . /lib/init/vars.sh . /lib/lsb/init-functions -# Try to extract nginx pidfile +# Try to extract llng-fastcgi-server pidfile if [ -z "$PID" ]; then PID=/run/llng-fastcgi-server.pid fi @@ -48,9 +39,9 @@ start_server() { # 0 if daemon has been started # 1 if daemon was already running # 2 if daemon could not be started - start-stop-daemon --start -c $USER:$GROUP --quiet --pidfile $PID --exec $DAEMON --test > /dev/null \ + start-stop-daemon --start --quiet --pidfile $PID --exec $DAEMON --test > /dev/null \ || return 1 - start-stop-daemon --start -c $USER:$GROUP --quiet --pidfile $PID --exec $DAEMON -- \ + start-stop-daemon --start --quiet --pidfile $PID --exec $DAEMON -- \ $DAEMON_OPTS 2>/dev/null \ || return 2 } @@ -69,6 +60,12 @@ stop_server() { return "$RETVAL" } +reload_server() { + # Function that sends a SIGHUP to the daemon/service + start-stop-daemon --stop --signal HUP --quiet --pidfile $PID --name $NAME + return 0 +} + case "$1" in start) log_daemon_msg "Starting $DESC" "$NAME" @@ -86,10 +83,10 @@ case "$1" in 2) log_end_msg 1 ;; esac ;; - restart|force-reload) + restart) log_daemon_msg "Restarting $DESC" "$NAME" - # Check configuration before stopping nginx + # Check configuration before stopping llng-fastcgi-server if ! test_config; then log_end_msg 1 # Configuration error exit $? @@ -111,11 +108,16 @@ case "$1" in ;; esac ;; + reload|force-reload) + log_daemon_msg "Reloading $DESC configuration" "$NAME" + reload_server + log_end_msg $? + ;; status) status_of_proc -p $PID "$DAEMON" "$NAME" && exit 0 || exit $? ;; *) - echo "Usage: $NAME {start|stop|restart|force-reload|status}" >&2 + echo "Usage: $NAME {start|stop|restart|reload|force-reload|status}" >&2 exit 3 ;; esac diff --git a/fastcgi-server/sbin/llng-fastcgi-server b/fastcgi-server/sbin/llng-fastcgi-server new file mode 100644 index 000000000..4cfffe568 --- /dev/null +++ b/fastcgi-server/sbin/llng-fastcgi-server @@ -0,0 +1,75 @@ +#!/usr/bin/env perl + +use Plack::Runner; +use strict; +use warnings; +use POSIX; +use Getopt::Std; + +our %opts; +my %_apps; + +getopts( 'n:p:s:u:g:', \%opts ); + +$opts{n} ||= $ENV{NPROC} || 7; +$opts{p} ||= $ENV{PID} || '/run/llng-fastcgi.pid'; +$opts{s} ||= $ENV{SOCKET} || '/run/llng-fastcgi.sock'; +$opts{a} ||= $ENV{PORTAL_PATH} || '/var/lib/lemonldap-ng/portal'; +$opts{u} ||= $ENV{USER}; +$opts{g} ||= $ENV{GROUP}; + +if ( $opts{g} ) { + my $grp = getgrnam( $opts{g} ) or warn "Can't change uid to $opts{g}"; + POSIX::setuid($grp); +} + +if ( $opts{u} ) { + my $uid = getpwnam( $opts{u} ) or warn "Can't change uid to $opts{u}"; + POSIX::setuid($uid); +} + +my %builder = ( + handler => sub { + require Lemonldap::NG::Handler::Nginx; + return Lemonldap::NG::Handler::Nginx->run( {} ); + }, + manager => sub { + require Lemonldap::NG::Manager; + return Lemonldap::NG::Manager->run( {} ); + }, + auth => sub { + require CGI::Emulate::PSGI; + require CGI::Compile; + return CGI::Emulate::PSGI->handler( + CGI::Compile->compile("$opts{a}/index.pl") ); + }, +); + +unless ($>) { + die "Refuse to run as root. Aborting"; +} + +my $app = sub { + my $type = $_[0]->{LLTYPE} || 'handler'; + return $_apps{$type}->(@_) if ( defined $_apps{$type} ); + if ( defined $builder{$type} ) { + $_apps{$type} = $builder{$type}->(); + return $_apps{$type}->(@_); + } + die "Unknown PSGI type $type"; +}; + +my $server = Plack::Runner->new(); +$server->parse_options( + '-s' => 'FCGI', + '-E' => 'deployment', + '--pid' => $opts{p}, + '--nproc' => $opts{n}, + '--listen' => [ $opts{s} ], + '--proc-title' => 'llng-fastcgi-server', + '--daemonize', + '--no-default-middleware', +); + +$server->run($app); +