From b750078af620edc1c8cc7c0caf5a1851d63a1f12 Mon Sep 17 00:00:00 2001 From: Rezende & Pedro & Carlos & Raphael Date: Thu, 11 Sep 2014 17:05:20 -0300 Subject: [PATCH] - adding and authenticating users to/through LDAP - reasons for applying - emails to PIs and user signed-up - PIs only validates users from the authority --- portal/emailactivationview.py | 21 +- portal/homeview.py | 321 ++++++++++++++---- portal/lsapiclient.py | 5 +- portal/managementtabrequests.py | 16 +- portal/registrationview.py | 3 +- portal/templates/email_activation.html | 3 +- .../fibre__widget-login-fed-manager.html | 4 +- .../fibre/fibre__widget-topmenu.html | 12 +- .../templates/fibre/fibre_activate_user.html | 3 +- .../fibre/fibre_user_register_complete.html | 2 +- portal/templates/management-tab-requests.html | 213 ++++++------ 11 files changed, 425 insertions(+), 178 deletions(-) diff --git a/portal/emailactivationview.py b/portal/emailactivationview.py index 2a3e6179..e1a6a4be 100644 --- a/portal/emailactivationview.py +++ b/portal/emailactivationview.py @@ -2,7 +2,7 @@ from unfold.loginrequired import FreeAccessView # from manifold.core.query import Query from manifoldapi.manifoldapi import execute_query, execute_admin_query -from portal.actions import manifold_update_user, manifold_update_account, manifold_add_account, manifold_delete_account, sfa_update_user, authority_get_pi_emails +from portal.actions import manifold_update_user, manifold_update_account, manifold_add_account, manifold_delete_account, sfa_update_user, authority_get_pi_emails, authority_get_pis # from unfold.page import Page from ui.topmenu import topmenu_items_live, the_user @@ -14,7 +14,7 @@ from myslice.theme import ThemeView from portal.models import PendingUser from django.core.mail import EmailMultiAlternatives, send_mail from django.contrib.sites.models import Site - +from django.contrib.auth.models import User # import json, os, re, itertools @@ -50,6 +50,23 @@ class ActivateEmailView(FreeAccessView, ThemeView): PendingUser.objects.filter(email_hash__iexact = hash_code).update(status='True') activation = 'success' # sending email after activation success + try: + request = PendingUser.objects.filter(email_hash= hash_code) + split_authority_hrn = request[0].authority_hrn.split('.')[0] + pis = authority_get_pis(request, split_authority_hrn) + pi_emails = [] + for x in pis: + for e in x['pi_users']: + u = e.split('.')[1] + y = User.Objects.get(username = u) + if y.username.count("@") != 0: + if y.username.split("@")[1] == request[0].user_hrn.split("@")[1]: + pi_emails += [y.email] + subject = 'User email activated' + msg = 'The user %s has validated his/her email. Now you can validate his/her account' % (request[0].login) + send_mail(subject, msg, 'support@fibre.org.br', pi_emails, fail_silently = False) + except: + print "error sending the email!" #try: # Send an email: the recipients are the PI of the authority # If No PI is defined for this Authority, send to a default email (different for each theme) diff --git a/portal/homeview.py b/portal/homeview.py index 8bde68ca..7efd4205 100644 --- a/portal/homeview.py +++ b/portal/homeview.py @@ -1,7 +1,7 @@ # this somehow is not used anymore - should it not be ? from django.core.context_processors import csrf from django.http import HttpResponseRedirect -from django.contrib.auth import authenticate, login, logout +from django.contrib.auth import authenticate, login, logout, get_user_model from django.template import RequestContext from django.shortcuts import render_to_response from django.shortcuts import render @@ -10,7 +10,20 @@ import json from unfold.loginrequired import FreeAccessView from manifold.core.query import Query -from manifoldapi.manifoldapi import execute_query +#from manifoldapi.manifoldapi import execute_query +# LDAP query admin // If transfer this code to actions.py maybe don't need more execute_admin_query +from manifoldapi.manifoldapi import execute_query, execute_admin_query +# Edelberto - LDAP XXX +from portal.models import PendingUser +from django.contrib.auth.models import User #Pedro +from portal.actions import create_pending_user, create_user +from registrationview import RegistrationView +from random import randint +from hashlib import md5 +from django.contrib.sites.models import Site +import os.path, re +################## + from manifoldapi.manifoldresult import ManifoldResult from ui.topmenu import topmenu_items, the_user @@ -18,6 +31,9 @@ from myslice.configengine import ConfigEngine from myslice.theme import ThemeView +# Edelberto LDAP authentication XXX +import ldap + class HomeView (FreeAccessView, ThemeView): template_name = 'home-view.html' @@ -37,66 +53,249 @@ class HomeView (FreeAccessView, ThemeView): # LDAP form - If FIBRE, then get the possibilite to authenticate using usernameldap #if self.theme == 'fibre': - usernameldap = request.POST.get('usernameldap') - token = {'usernameldap': usernameldap, 'username': username ,'password': password, 'request': request} + #usernameldap = request.POST.get('usernameldap') + #token = {'usernameldap': usernameldap, 'username': username ,'password': password, 'request': request} + + ################################################## + ########## XXX Edelberto 010914 XXX + ################################################# + ## first you must open a connection to the server + try: + # Connect to NOC + l = ldap.initialize("ldap://200.130.15.186:389") + # Bind/authenticate with a root user to search all objects + l.simple_bind_s("cn=Manager,dc=br,dc=fibre","fibre2013") + + l.protocol_version = ldap.VERSION3 + except ldap.LDAPError, e: + print e + + ## Base directory + baseDN = "dc=fibre" + searchScope = ldap.SCOPE_SUBTREE + ## retrieve all attributes + retrieveAttributes = None + #retrieveAttributes = ['userEnable'] + searchFilter = "uid=" + username + print searchFilter + + try: + ldap_result_id = l.search(baseDN, searchScope, searchFilter, retrieveAttributes) + result_set = [] + result_type, result_data = l.result(ldap_result_id, 0) + if (result_data == []): + print "User doesnt exist in LDAP" + in_ldap = 0 + else: + if result_type == ldap.RES_SEARCH_ENTRY: + result_set.append(result_data) + else: + result_set.append(result_data) + # TRUE or FALSE for userEnable attribute + userEnable = result_set[0][0][1]['userEnable'][0] + if userEnable == 'TRUE': + in_ldap = 1 + enabled = 1 + print "In LDAP and Enabled" + + dn = result_set[0][0][0] + try: + l.simple_bind_s(dn,password) + pwd = 1 + print "User password OK" + + except: + pwd = 0 + print "User password WRONG" + + if in_ldap and enabled and pwd: + ldap_mail = result_set[0][0][1]['mail'][0] + + user_exists = Query().get('local:user') \ + .select('status') \ + .filter_by('email', '==', username) + results = execute_admin_query(request, user_exists) + print "DEBUG: %s" % user_exists + if results: + print "DEBUG: user exists on MySlice DBs" + else: + print "DEBUG: user NOT exists on MySlice DBs" + + cn = result_set[0][0][1]['cn'][0] + print cn + sn = result_set[0][0][1]['sn'][0] + print sn + authority_hrn = 'fibre' + '.' + username.split('@')[1] + print authority_hrn + email = ldap_mail + print ldap_mail + username = username + print username + password = password + print password + user_hrn = 'fibre' + '.' + username.split('@')[1] + '.' + username + print user_hrn + + # Based on registrationview + + + # get the domain url + current_site = Site.objects.get_current() + current_site = current_site.domain + print current_site + + post_email = ldap_mail + salt = randint(1,100000) + email_hash = md5(str(salt)+post_email).hexdigest() + print email_hash + + user_request = { + #'first_name' : cn, + 'first_name' : sn, + 'last_name' : '', + #'organization' : username.split('@')[1], + 'organization' : authority_hrn, + 'authority_hrn' : authority_hrn, + 'email' : ldap_mail, + 'username' : username, + 'password' : password, + 'current_site' : current_site, + 'email_hash' : email_hash, + 'pi' : '', + 'user_hrn' : user_hrn, + 'type' : 'user', + 'validation_link': 'https://' + current_site + '/portal/email_activation/'+ email_hash + } + + # Validate input + errors = [] + UserModel = get_user_model() + if (re.search(r'^[\w+\s.@+-]+$', user_request['first_name']) == None): + errors.append('First name may contain only letters, numbers, spaces and @/./+/-/_ characters.') + if (re.search(r'^[\w+\s.@+-]+$', user_request['last_name']) == None): + errors.append('Last name may contain only letters, numbers, spaces and @/./+/-/_ characters.') + if (re.search(r'^[\w,]+$' , username) == None): + errors.append('Username may contain only letters,numbers and -/_ characters.') + # checking in django_db !! + if PendingUser.objects.filter(email__iexact = user_request['email']): + errors.append('Email is pending for validation. Please provide a new email address.') + if User.objects.filter(username__iexact = user_request['username']): + errors.append('This username is already in use, try another one') + # Does the user exist in Manifold? + user_query = Query().get('local:user').select('user_id','email') + user_details = execute_admin_query(request, user_query) + for user_detail in user_details: + if user_detail['email'] == user_request['email']: + errors.append('Email already registered in Manifold. Please provide a new email address.') + # Does the user exist in sfa? [query is very slow!!] + #user_query = Query().get('user').select('user_hrn','user_email') + # XXX Test based on the user_hrn is quick + #user_query = Query().get('user').select('user_hrn','user_email').filter_by('user_hrn','==',user_request['user_hrn']) + user_query = Query().get('user').select('user_hrn','user_email').filter_by('user_hrn','==',user_hrn) + user_details_sfa = execute_admin_query(request, user_query) + + #if 'generate' in wsgi_request.POST['question']: + user_request['auth_type'] = 'managed' + + # XXX Common code, dependency ? + from Crypto.PublicKey import RSA + private = RSA.generate(1024) + + # Example: private_key = '-----BEGIN RSA PRIVATE KEY-----\nMIIC...' + # Example: public_key = 'ssh-rsa AAAAB3...' + user_request['private_key'] = private.exportKey() + user_request['public_key'] = private.publickey().exportKey(format='OpenSSH') + + # XXX Verify if errors exist - After! + #if not errors: + create_pending_user(request, user_request, user_detail) + + create_user(request, user_request) + + env['state'] = "User LDAP associated. Authenticate again." + return render_to_response(self.template, env, context_instance=RequestContext(request)) + + + else: + env['state'] = "Access denied. Verify LDAP userEnable and password." + return render_to_response(self.template, env, context_instance=RequestContext(request)) + + else: + in_ldap = 1 + enabled = 0 + print "In LDAP but Disabled" + env['state'] = "Access denied. Verify LDAP userEnable." + return render_to_response(self.template, env, context_instance=RequestContext(request)) + + #print result_set + except ldap.LDAPError, e: + print e + #else: - - # Follow original code - ## pass request within the token, so manifold session key can be attached to the request session. - #token = {'username': username, 'password': password, 'request': request} - - # our authenticate function returns either - # . a ManifoldResult - when something has gone wrong, like e.g. backend is unreachable - # . a django User in case of success - # . or None if the backend could be reached but the authentication failed - auth_result = authenticate(token=token) - # use one or two columns for the layout - not logged in users will see the login prompt - # high-level errors, like connection refused or the like - if isinstance (auth_result, ManifoldResult): - manifoldresult = auth_result - # let's use ManifoldResult.__repr__ - env['state']="%s"%manifoldresult - - return render_to_response(self.template,env, context_instance=RequestContext(request)) - # user was authenticated at the backend - elif auth_result is not None: - user=auth_result - if user.is_active: - print "LOGGING IN" - login(request, user) - - if request.user.is_authenticated(): - env['person'] = self.request.user - env['username'] = self.request.user - - ## check user is pi or not - platform_query = Query().get('local:platform').select('platform_id','platform','gateway_type','disabled') - account_query = Query().get('local:account').select('user_id','platform_id','auth_type','config') - platform_details = execute_query(self.request, platform_query) - account_details = execute_query(self.request, account_query) - for platform_detail in platform_details: - for account_detail in account_details: - if platform_detail['platform_id'] == account_detail['platform_id']: - if 'config' in account_detail and account_detail['config'] is not '': - account_config = json.loads(account_detail['config']) - if 'myslice' in platform_detail['platform']: - acc_auth_cred = account_config.get('delegated_authority_credentials','N/A') - # assigning values - if acc_auth_cred=={} or acc_auth_cred=='N/A': - pi = "is_not_pi" - else: - pi = "is_pi" - - env['pi'] = pi - else: - env['person'] = None - return render_to_response(self.template,env, context_instance=RequestContext(request)) - else: - env['state'] = "Your account is not active, please contact the site admin." - env['layout_1_or_2']="layout-unfold2.html" - - return render_to_response(self.template,env, context_instance=RequestContext(request)) - # otherwise + if in_ldap and enabled and pwd: + +################################################################################ +### XXX Edelberto LDAP auth end XXX +############################################################################### + # Follow original code + ## pass request within the token, so manifold session key can be attached to the request session. + token = {'username': username, 'password': password, 'request': request} + + # our authenticate function returns either + # . a ManifoldResult - when something has gone wrong, like e.g. backend is unreachable + # . a django User in case of success + # . or None if the backend could be reached but the authentication failed + auth_result = authenticate(token=token) + # use one or two columns for the layout - not logged in users will see the login prompt + # high-level errors, like connection refused or the like + if isinstance (auth_result, ManifoldResult): + manifoldresult = auth_result + # let's use ManifoldResult.__repr__ + env['state']="%s"%manifoldresult + + return render_to_response(self.template,env, context_instance=RequestContext(request)) + # user was authenticated at the backend + elif auth_result is not None: + user=auth_result + if user.is_active: + print "LOGGING IN" + login(request, user) + + if request.user.is_authenticated(): + env['person'] = self.request.user + env['username'] = self.request.user + + ## check user is pi or not + platform_query = Query().get('local:platform').select('platform_id','platform','gateway_type','disabled') + account_query = Query().get('local:account').select('user_id','platform_id','auth_type','config') + + # Edleberto + #cc_auth_cred = {} + + platform_details = execute_query(self.request, platform_query) + account_details = execute_query(self.request, account_query) + for platform_detail in platform_details: + for account_detail in account_details: + if platform_detail['platform_id'] == account_detail['platform_id']: + if 'config' in account_detail and account_detail['config'] is not '': + account_config = json.loads(account_detail['config']) + if 'myslice' in platform_detail['platform']: + acc_auth_cred = account_config.get('delegated_authority_credentials','N/A') + # assigning values + if acc_auth_cred=={} or acc_auth_cred=='N/A': + pi = "is_not_pi" + else: + pi = "is_pi" + env['pi'] = pi + else: + env['person'] = None + return render_to_response(self.template,env, context_instance=RequestContext(request)) + else: + env['state'] = "Your account is not active, please contact the site admin." + env['layout_1_or_2']="layout-unfold2.html" + + return render_to_response(self.template,env, context_instance=RequestContext(request)) + # otherwise else: env['state'] = "Your username and/or password were incorrect." diff --git a/portal/lsapiclient.py b/portal/lsapiclient.py index 494adb0d..16287082 100644 --- a/portal/lsapiclient.py +++ b/portal/lsapiclient.py @@ -16,8 +16,9 @@ class LaboraSchedulerClient: 'get_user_id_by_username' ] def __init__ ( self, organization ): - self.url, self.key = self.getOrganizationConfigs( organization ) - + # self.url, self.key = self.getOrganizationConfigs( organization ) + self.url = "https://portal.ufrj.fibre.org.br:3002/LS-Sched/" + self.key = "9763dd03f2da8138fb22a63d78e5e9792b59a637" def __getattr__(self, name): diff --git a/portal/managementtabrequests.py b/portal/managementtabrequests.py index 6e8a19d2..0f490e94 100644 --- a/portal/managementtabrequests.py +++ b/portal/managementtabrequests.py @@ -165,13 +165,23 @@ class ManagementRequestsView (LoginRequiredView, ThemeView): # env['theme'] = self.theme # env['section'] = "Requests" # auth_hrn = user_authority + '.' + user_username.split("@")[1] - auth_hrn = user_username.split("@")[1] + ctx_list = [ctx_my_authorities, ctx_sub_authorities, ctx_delegation_authorities] + for ctx in ctx_list: + if ctx: + for authorities in ctx: + for requests in ctx[authorities]: + try: + requests['object_auth'] = requests['user_hrn'].split('.')[0] + '.' + requests['user_hrn'].split('@')[1] + except: + print "This object has no user_hrn" + + pi_authority = user_authority + '.' + user_username.split("@")[1] context = super(ManagementRequestsView, self).get_context_data(**kwargs) print "testing" print ctx_my_authorities print auth_hrn print user_username - print user_authority + print pi_authority context['my_authorities'] = ctx_my_authorities context['sub_authorities'] = ctx_sub_authorities context['delegation_authorities'] = ctx_delegation_authorities @@ -186,7 +196,7 @@ class ManagementRequestsView (LoginRequiredView, ThemeView): context['pi'] = "is_pi" context['theme'] = self.theme context['section'] = "Requests" - context['auth_hrn'] = auth_hrn + context['pi_authority'] = pi_authority # XXX We need to prepare the page for queries #context.update(page.prelude_env()) diff --git a/portal/registrationview.py b/portal/registrationview.py index 06ca983f..25a050a8 100644 --- a/portal/registrationview.py +++ b/portal/registrationview.py @@ -192,7 +192,8 @@ class RegistrationView (FreeAccessView, ThemeView): 'topmenu_items': topmenu_items_live('Register', page), 'errors': errors, 'authorities': authorities, - 'theme': self.theme + 'theme': self.theme, + 'section':'Registration' } template_env.update(user_request) template_env.update(reg_form) diff --git a/portal/templates/email_activation.html b/portal/templates/email_activation.html index 43feab20..0ad87694 100644 --- a/portal/templates/email_activation.html +++ b/portal/templates/email_activation.html @@ -7,8 +7,7 @@
{%if activation_status == 'success'%} -

Signup request confirmed.

-

You are currently able to log in to the portal using your email address and the password that you provided, but your access is still limited.

+

Signup request confirmed.

You will have full access as soon as your account is validated by a manager at your organization. We have sent an email to the managers with a validation request.

{%else%}

Signup confirmation failed.

diff --git a/portal/templates/fibre/fibre__widget-login-fed-manager.html b/portal/templates/fibre/fibre__widget-login-fed-manager.html index a67e2ddb..181fe83b 100644 --- a/portal/templates/fibre/fibre__widget-login-fed-manager.html +++ b/portal/templates/fibre/fibre__widget-login-fed-manager.html @@ -17,8 +17,8 @@
- - + +
diff --git a/portal/templates/fibre/fibre__widget-topmenu.html b/portal/templates/fibre/fibre__widget-topmenu.html index 09d3acfb..a3ed9ff4 100644 --- a/portal/templates/fibre/fibre__widget-topmenu.html +++ b/portal/templates/fibre/fibre__widget-topmenu.html @@ -34,11 +34,13 @@
  • About
  • Public Website
  • - {% if username %} - {% if person.username %} - - {% else %} - + {% if section != 'Registration' %} + {% if username %} + {% if person.username %} + + {% else %} + + {% endif %} {% endif %} {% endif %}
    diff --git a/portal/templates/fibre/fibre_activate_user.html b/portal/templates/fibre/fibre_activate_user.html index 35936393..b5f3e734 100644 --- a/portal/templates/fibre/fibre_activate_user.html +++ b/portal/templates/fibre/fibre_activate_user.html @@ -6,11 +6,12 @@ Organization: {{organization}}
    First name: {{first_name}}
    Last name: {{last_name}}
    +Username : {{ username }}
    Email: {{email}}

    -You may now log in to the portal using your email address and the password that you provided, but your access will be limited. To gain full access, two steps are required: + To gain full access, two steps are required: