Skip to content
This repository has been archived by the owner on Mar 29, 2024. It is now read-only.

Commit

Permalink
ADwebmanager v1.0 rc1
Browse files Browse the repository at this point in the history
[In this commit]
-New Configuration system, using an object for holding the config data. Includes new EXTRA_FIELDS, ADMIN_GROUP and SEARCH_ATTRS options.
-Way less hardcoded configuration
-New Background.
-New Footer and copyright.

[In this release]
-Complete Python 3.8 compatibility.
-Redesign visual style.
-New Search bar in the tree view.
-Lots of bug fixes!!!
  • Loading branch information
VicentGJ committed Jan 4, 2021
1 parent b0bb10f commit bbcb1bb
Show file tree
Hide file tree
Showing 12 changed files with 174 additions and 51 deletions.
140 changes: 140 additions & 0 deletions ADwebmanager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#!/usr/bin/python2
# -*- coding: utf-8 -*-

# Copyright (C) 2012-2015 Stéphane Graber
# Author: Stéphane Graber <[email protected]>

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You can find the license on Debian systems in the file
# /usr/share/common-licenses/GPL-2

import argparse
import os

app_prefix = "/opt/samba4-manager-master/"

# Check if running from bzr
for path in ('libs', 'plugins', 'static', 'templates'):
if not os.path.exists(path):
break
else:
app_prefix = "."

parser = argparse.ArgumentParser(description="Samba4 Gestor Web")
args = parser.parse_args()

if not os.path.exists(app_prefix):
raise Exception("Missing app dir: %s" % app_prefix)

# Import the rest of the stuff we need
from flask import Flask, g
import glob
import importlib

# Look at the right place
import sys
sys.path.append(app_prefix)

# Import our modules
from libs.common import ReverseProxied
from libs.common import iri_for as url_for
from settings import Settings

# Prepare the web server
app = Flask(__name__,
static_folder="%s/static" % app_prefix,
template_folder="%s/templates" % app_prefix)

app.config.from_object(Settings)
app.jinja_env.globals['url_for'] = url_for

if 'URL_PREFIX' in app.config:
app.wsgi_app = ReverseProxied(app.wsgi_app, app.config['URL_PREFIX'])

# Check for mandatory configuration
for key in ("LDAP_DOMAIN", "SECRET_KEY", "SEARCH_DN"):
if key not in app.config:
raise KeyError("Missing mandatory %s option in configuration." % key)

# LDAP configuration
if "LDAP_DN" not in app.config:
app.config['LDAP_DN'] = "DC=%s" % ",DC=".join(
app.config['LDAP_DOMAIN'].split("."))

if "LDAP_SERVER" not in app.config:
import dns.resolver
import dns.rdatatype
import operator

record = "_ldap._tcp.%s." % app.config['LDAP_DOMAIN']
answers = []

# Query the DNS
try:
for answer in dns.resolver.query(record, dns.rdatatype.SRV):
address = (answer.target.to_text()[:-1], answer.port)
answers.append((address, answer.priority, answer.weight))
except:
# Ignore exceptions, an empty list will trigger an exception anyway
pass

# Order by priority and weight
servers = [entry[0][0] for entry in sorted(answers,
key=operator.itemgetter(1, 2))]
if not servers:
raise Exception("No LDAP server in domain '%s'." %
app.config['LDAP_DOMAIN'])

if len(servers) == 1:
app.config['LDAP_SERVER'] = servers[0]
else:
app.config['LDAP_SERVER'] = servers

if "SICCIP_AWARE" not in app.config:
app.config['SICCIP_AWARE'] = False

# Load the plugins
for plugin_file in glob.glob("%s/plugins/*.py" % app_prefix):
plugin_name = plugin_file.split('/')[-1].replace('.py', '')
if plugin_name == "__init__":
continue

plugin = importlib.import_module("plugins.%s" % plugin_name)
plugin.init(app)


@app.before_request
def pre_request():
"""
Setup any of the global variables before the request is processed.
"""
g.menu = []
g.menu.append((url_for("core_index"), "Mi Cuenta"))
g.menu.append((url_for("tree_base"), u"Directorio"))
g.menu.append((url_for("core_logout"), "Log out"))

# LDAP connection settings
g.ldap = {'domain': app.config['LDAP_DOMAIN'], 'dn': app.config['LDAP_DN'], 'server': app.config['LDAP_SERVER'],
'search_dn': app.config['SEARCH_DN']}

# The various caches

g.ldap_cache = {}

# SICC-IP integrations
g.siccip = app.config['SICCIP_AWARE']
# Extra fields form
g.extra_fields = app.config['EXTRA_FIELDS']


if __name__ == '__main__':
app.run(host='::', port=8080)
7 changes: 0 additions & 7 deletions libs/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,3 @@ def get_parsed_pager_attribute(pager):
'email_quota': email_quota, 'dansguardian_filter': dansguardian_filter_number}
except ValueError:
return None


def parse_settings(setting):
parser = SafeConfigParser()

parser.read('settings.cfg')
return parser.get('SETTINGS', setting)
10 changes: 0 additions & 10 deletions manager.cfg

This file was deleted.

14 changes: 8 additions & 6 deletions plugins/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
# /usr/share/common-licenses/GPL-2

from libs.common import iri_for as url_for
from libs.common import parse_settings as settings
from settings import Settings
from flask import abort, flash, g, render_template, redirect, request
from flask_wtf import FlaskForm
from wtforms import RadioField, TextAreaField, TextField, HiddenField
Expand All @@ -31,9 +31,11 @@
import ldap
import struct


class GroupDelMember(FlaskForm):
pass


class GroupAddMembers(FlaskForm):
new_members = TextAreaField('Nuevos miembros')

Expand All @@ -51,7 +53,7 @@ class GroupEdit(FlaskForm):

def init(app):
@app.route('/groups/+add', methods=['GET', 'POST'])
@ldap_auth(settings('ADMIN_GROUP'))
@ldap_auth(Settings.ADMIN_GROUP)
def group_add():
title = "Adicionar grupo"

Expand Down Expand Up @@ -149,7 +151,7 @@ def group_overview(groupname):
grouptype_values=LDAP_AD_GROUPTYPE_VALUES)

@app.route('/group/<groupname>/+delete', methods=['GET', 'POST'])
@ldap_auth(settings('ADMIN_GROUP'))
@ldap_auth(Settings.ADMIN_GROUP)
def group_delete(groupname):
title = "Eliminar grupo"

Expand Down Expand Up @@ -178,7 +180,7 @@ def group_delete(groupname):
groupname=groupname))

@app.route('/group/<groupname>/+edit', methods=['GET', 'POST'])
@ldap_auth(settings('ADMIN_GROUP'))
@ldap_auth(Settings.ADMIN_GROUP)
def group_edit(groupname):
title = "Editar grupo"

Expand Down Expand Up @@ -253,7 +255,7 @@ def group_edit(groupname):
groupname=groupname))

@app.route('/group/<groupname>/+add-members', methods=['GET', 'POST'])
@ldap_auth(settings('ADMIN_GROUP'))
@ldap_auth(Settings.ADMIN_GROUP)
def group_addmembers(groupname):
title = "Adicionar miembros"

Expand Down Expand Up @@ -298,7 +300,7 @@ def group_addmembers(groupname):

@app.route('/group/<groupname>/+del-member/<member>',
methods=['GET', 'POST'])
@ldap_auth(settings('ADMIN_GROUP'))
@ldap_auth(Settings.ADMIN_GROUP)
def group_delmember(groupname, member):
title = "Quitar del grupo"

Expand Down
8 changes: 3 additions & 5 deletions plugins/tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
# /usr/share/common-licenses/GPL-2

from libs.common import iri_for as url_for
from libs.common import parse_settings as settings
from settings import Settings
from flask import g, render_template, request, redirect, abort
from libs.ldap_func import ldap_auth, ldap_get_entries, ldap_in_group
from flask_wtf import FlaskForm
Expand All @@ -31,9 +31,7 @@
# TODO: most here are CUJAE specific, refactor for master
class FilterTreeView(FlaskForm):
filter_str = StringField()
filter_select = SelectField(choices=[('cUJAEPersonDNI', 'Carné ID'),
('sAMAccountName', 'Usuario'),
('givenName', 'Nombre')])
filter_select = SelectField(choices=Settings.SEARCH_ATTRS)


def init(app):
Expand All @@ -46,7 +44,7 @@ def tree_base(base=None):
elif not base.lower().endswith(g.ldap['dn'].lower()):
base += ",%s" % g.ldap['dn']

admin = ldap_in_group(settings('ADMIN_GROUP'))
admin = ldap_in_group(Settings.ADMIN_GROUP)

if not admin:
abort(401)
Expand Down
18 changes: 9 additions & 9 deletions plugins/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
# /usr/share/common-licenses/GPL-2

from libs.common import iri_for as url_for
from libs.common import parse_settings as settings
from settings import Settings
from flask import abort, flash, g, render_template, redirect, request
from flask_wtf import FlaskForm
from wtforms import PasswordField, SelectMultipleField, TextAreaField, \
Expand Down Expand Up @@ -101,7 +101,7 @@ class PasswordChangeUser(PasswordChange):

def init(app):
@app.route('/users/+add', methods=['GET', 'POST'])
@ldap_auth(settings("ADMIN_GROUP")) # TODO: Change this for master
@ldap_auth(Settings.ADMIN_GROUP)
def user_add():
title = "Adicionar Usuario"

Expand Down Expand Up @@ -189,7 +189,7 @@ def user_overview(username):
abort(404)

user = ldap_get_user(username=username)
admin = ldap_in_group(settings('ADMIN_GROUP'))
admin = ldap_in_group(Settings.ADMIN_GROUP)
logged_user = g.ldap['username']

if logged_user == user['sAMAccountName'] or admin:
Expand Down Expand Up @@ -278,7 +278,7 @@ def user_changepw(username):
if not ldap_user_exists(username=username):
abort(404)

admin = ldap_in_group(settings('ADMIN_GROUP'))
admin = ldap_in_group(Settings.ADMIN_GROUP)

if username != g.ldap['username'] and admin:
form = PasswordChange(request.form)
Expand Down Expand Up @@ -313,7 +313,7 @@ def user_changepw(username):
username=username))

@app.route('/user/<username>/+delete', methods=['GET', 'POST'])
@ldap_auth(settings('ADMIN_GROUP')) # TODO: Change this for master
@ldap_auth(Settings.ADMIN_GROUP)
def user_delete(username):
title = "Borrar Usuario"

Expand Down Expand Up @@ -341,7 +341,7 @@ def user_delete(username):
username=username))

@app.route('/user/<username>/+edit-profile', methods=['GET', 'POST'])
@ldap_auth(settings('ADMIN_GROUP')) # TODO: Change this for master
@ldap_auth(Settings.ADMIN_GROUP)
def user_edit_profile(username):
title = "Editar usuario"

Expand Down Expand Up @@ -410,7 +410,7 @@ def user_edit_profile(username):
username=username))

@app.route('/user/<username>/+edit-siccip', methods=['GET', 'POST'])
@ldap_auth(settings('ADMIN_GROUP')) # TODO: Change this for master
@ldap_auth(Settings.ADMIN_GROUP)
def user_edit_siccip(username):
title = u"Editar Configuración SICC-IP"

Expand Down Expand Up @@ -467,7 +467,7 @@ def user_edit_siccip(username):
username=username))

@app.route('/user/<username>/+edit-ssh', methods=['GET', 'POST'])
@ldap_auth(settings('ADMIN_GROUP')) # TODO: Change this for master
@ldap_auth(Settings.ADMIN_GROUP)
def user_edit_ssh(username):
title = "Editar llaves SSH"

Expand Down Expand Up @@ -505,7 +505,7 @@ def user_edit_ssh(username):


# @app.route('/user/<username>/+edit-groups', methods=['GET', 'POST'])
# @ldap_auth(settings('ADMIN_GROUP')) # TODO: Change this for master
# @ldap_auth(Settings.ADMIN_GROUP)
# def user_edit_groups(username):
# title = "Editar pertenencia a Grupos"
#
Expand Down
10 changes: 0 additions & 10 deletions settings.cfg

This file was deleted.

11 changes: 11 additions & 0 deletions settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class Settings:
SECRET_KEY = "AHDGIWIWBQSBKQYUQXBXKGAsdhahdflkjfgierqhs"
LDAP_DOMAIN = "cujae.edu.cu"
SEARCH_DN = "dc=cujae,dc=edu,dc=cu"
LDAP_SERVER = "10.8.1.63"
DEBUG = True
# URL_PREFIX = "/domain"
SICCIP_AWARE = False
EXTRA_FIELDS = True
ADMIN_GROUP = "SM Admins"
SEARCH_ATTRS = [('cUJAEPersonDNI', 'Carné ID'), ('sAMAccountName', 'Usuario'), ('givenName', 'Nombre')]
2 changes: 1 addition & 1 deletion static/css/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ html, body {
}
body {
background: #054cde;
background-image: url("/static/img/BRcS1h.png");
background-image: url("/static/img/BRcS1h.jpeg");
background-attachment: fixed;
background-position: center;
background-size: cover;
Expand Down
Binary file added static/img/BRcS1h.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed static/img/BRcS1h.png
Binary file not shown.
5 changes: 2 additions & 3 deletions templates/base_es.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,8 @@ <h1 id="page-title">{{ self.title() }}</h1>

<div id="footer">
{% block footer %}{% endblock%}
<p>&copy; 2012-2015 Stéphane Graber. <a href="https://github.com/stgraber/samba4-manager"/>Samba4 web manager.</a></p>
<p>2017 - Traducción al español y adiciones menores por Alain Garófalo
<br>2020 - Rediseño, actualización a Python3.8 y adiciones por Vicente Garófalo </p>
<p>&copy; 2020-2021 Vicente y Alain Garófalo. <a href="https://github.com/VicentGJ/AD-webmanager"> AD WebManager</a>.</p>
<p>Basado en <a href="https://github.com/stgraber/samba4-manager">Samba4 web manager</a> de Stéphane Graber.</p>
<div class="clear"></div>
</div>
</div>
Expand Down

0 comments on commit bbcb1bb

Please sign in to comment.