Make SELinux happy
[cascardo/ipsilon.git] / ipsilon / login / authpam.py
index ce60f39..14ebae4 100755 (executable)
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 from ipsilon.login.common import LoginPageBase, LoginManagerBase
+from ipsilon.login.common import FACILITY
+from ipsilon.util.plugin import PluginObject
 import cherrypy
 import pam
+import subprocess
 
 
 class Pam(LoginPageBase):
@@ -38,36 +41,58 @@ class Pam(LoginPageBase):
         return None
 
     def GET(self, *args, **kwargs):
-        return self._template('login/pam.html', title='Login',
-                              action='%s/login/pam' % self.basepath,
-                              service_name=self.lm.service_name,
-                              username_text=self.lm.username_text,
-                              password_text=self.lm.password_text)
+        context = self.create_tmpl_context()
+        # pylint: disable=star-args
+        return self._template('login/pam.html', **context)
 
     def POST(self, *args, **kwargs):
-        username = None
-        password = None
+        username = kwargs.get("login_name")
+        password = kwargs.get("login_password")
         user = None
-        for key, value in kwargs.iteritems():
-            if key == 'login_name':
-                username = value
-            elif key == 'login_password':
-                password = value
-        if username is not None and password is not None:
-            user = self._authenticate(username, password)
-        else:
-            cherrypy.log.error("Error: Username or password is missing")
+        error = None
 
-        if user:
-            return self.lm.auth_successful(user)
+        if username and password:
+            user = self._authenticate(username, password)
+            if user:
+                return self.lm.auth_successful(user)
+            else:
+                error = "Authentication failed"
+                cherrypy.log.error(error)
         else:
-            return self.lm.auth_failed()
+            error = "Username or password is missing"
+            cherrypy.log.error("Error: " + error)
+
+        context = self.create_tmpl_context(
+            username=username,
+            error=error,
+            error_password=not password,
+            error_username=not username
+        )
+        # pylint: disable=star-args
+        return self._template('login/pam.html', **context)
 
     def root(self, *args, **kwargs):
         op = getattr(self, cherrypy.request.method, self.GET)
         if callable(op):
             return op(*args, **kwargs)
 
+    def create_tmpl_context(self, **kwargs):
+        next_url = None
+        if self.lm.next_login is not None:
+            next_url = self.lm.next_login.path
+
+        context = {
+            "title": 'Login',
+            "action": '%s/login/pam' % self.basepath,
+            "service_name": self.lm.service_name,
+            "username_text": self.lm.username_text,
+            "password_text": self.lm.password_text,
+            "description": self.lm.help_text,
+            "next_url": next_url,
+        }
+        context.update(kwargs)
+        return context
+
 
 class LoginManager(LoginManagerBase):
 
@@ -85,6 +110,11 @@ for authentication. """
                 'string',
                 'remote'
             ],
+            'help text': [
+                """ The text shown to guide the user at login time. """,
+                'string',
+                'Insert your Username and Password and then submit.'
+            ],
             'username text': [
                 """ The text shown to ask for the username in the form. """,
                 'string',
@@ -101,6 +131,10 @@ for authentication. """
     def service_name(self):
         return self.get_config_value('service name')
 
+    @property
+    def help_text(self):
+        return self.get_config_value('help text')
+
     @property
     def username_text(self):
         return self.get_config_value('username text')
@@ -112,3 +146,51 @@ for authentication. """
     def get_tree(self, site):
         self.page = Pam(site, self)
         return self.page
+
+
+class Installer(object):
+
+    def __init__(self):
+        self.name = 'pam'
+        self.ptype = 'login'
+
+    def install_args(self, group):
+        group.add_argument('--pam', choices=['yes', 'no'], default='no',
+                           help='Configure PAM authentication')
+        group.add_argument('--pam-service', action='store', default='remote',
+                           help='PAM service name to use for authentication')
+
+    def configure(self, opts):
+        if opts['pam'] != 'yes':
+            return
+
+        # Add configuration data to database
+        po = PluginObject()
+        po.name = 'pam'
+        po.wipe_data()
+
+        po.wipe_config_values(FACILITY)
+        config = {'service name': opts['pam_service']}
+        po.set_config(config)
+        po.save_plugin_config(FACILITY)
+
+        # Update global config to add login plugin
+        po = PluginObject()
+        po.name = 'global'
+        globalconf = po.get_plugin_config(FACILITY)
+        if 'order' in globalconf:
+            order = globalconf['order'].split(',')
+        else:
+            order = []
+        order.append('pam')
+        globalconf['order'] = ','.join(order)
+        po.set_config(globalconf)
+        po.save_plugin_config(FACILITY)
+
+        # for selinux enabled platfroms, ignore if it fails just report
+        try:
+            subprocess.call(['/usr/sbin/setsebool', '-P',
+                             'httpd_mod_auth_pam=on',
+                             'httpd_tmp_t=on'])
+        except Exception:  # pylint: disable=broad-except
+            pass