-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
32 changed files
with
408 additions
and
269 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
[flake8] | ||
max-line-length = 120 | ||
statistics = True | ||
exclude = venv,migrations,members/settings.py |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
Contributing | ||
=== | ||
|
||
Hi there ! Welcome to the contribution documentation of this project ! | ||
|
||
Developing on members.atilla.org is fairly easy compared to many other Open Source projects, but in order to keep a clean organization and a clean code base, here are some informations and guidelines that we encourage you to follow in your development process. | ||
|
||
Project Licensing | ||
--- | ||
|
||
This project is using a [MIT license](https://opensource.org/licenses/MIT) registered in the name of the Association ATILLA. Therefore, every code addition made on this project repository should agree with this license and, by doing so, the original code author (which can be you !) agrees that he can’t be held liable for the work he has done on the platform (for more resources, see https://tldrlegal.com/license/mit-license). | ||
|
||
Issues management | ||
--- | ||
|
||
Every code added, modified or deleted on the platform should be linked to a GitLab issue. This allows every developer on the project to be kept informed of new features, bugs or proposals. | ||
|
||
Please don’t use issues to discuss about a code change you made ; discussions revolving around a patch must be contained in the associated merge request. | ||
|
||
Branching model | ||
--- | ||
|
||
The project is composed of 3 main branches : `master`, `preprod` and `dev`. | ||
|
||
* `master` is updated every time a new version or a hotfix is released, every new commit on `master` gets a tag assigned to specify the platform version. | ||
* `preprod` is (sometimes) used to test the platform versions before released. | ||
* `dev` contains the last version of the platform currently in development. Theoretically, every new code added, modified or deleted on the platform should come from a merge request made on `dev`. Then, `dev` is merged onto `preprod` or `master`. | ||
|
||
As we need to keep our code base as clean as possible, currently no direct commit are allowed on `dev`, `preprod` or `master` and merge requests can only be accepted if the CI linked to this project does not fail. | ||
|
||
The naming of development branches isn’t really restricted, but we encourage you to use prefixes in your branch names such as `feature/` or `fix/` in order to make them more distinguishable. | ||
|
||
Syntax | ||
--- | ||
|
||
Code usually goes through [`pep8`](https://www.python.org/dev/peps/pep-0008/) validation. You can check your code syntax by using `flake8`, a pip package provided in the `requirements-tests.txt` file. | ||
|
||
Documentation | ||
--- | ||
|
||
Currently, we don’t have any guideline regarding code documentation, if we want the project to evolve cleanly, we might have to fix that. | ||
|
||
However, if you fell like it, you can contribute to the user / administrator documentation available on [this wiki page](https://wiki.atilla.org/index.php?title=Members.atilla.org) (in french). | ||
|
||
Developer workflow guide | ||
=== | ||
|
||
If you ever feel lost in your development process, here is a simple guide that you can follow : | ||
|
||
1. Supposing a bug or a feature has been notified by the users, this has to be reported on the project as an issue with a descriptive description and useful tags. | ||
2. A developer will then create a new branch based on `dev` where he'll make the necessary code changes. | ||
3. In case he needs advice from others, he can publish an early merge request for his branch to land onto `dev`, with the `WIP:` prefix, preventing the branch to be accidentally merged. | ||
4. Discussions revolving around a patch must be contained in the associated merge request. | ||
5. When the feature / bug is ready to review, the assignee is changed to one of the head developer of the project, and the `WIP:` prefix is removed (if present). | ||
6. Comments about the code shall be made directly through the Gitlab code comment feature. | ||
7. People can validate a merge request by posting in the MR comment section "LGTM". | ||
8. When everyone agrees, the MR is accepted. | ||
|
||
--- | ||
|
||
Finally, as a last advice, do not hesitate to contact the project developers if you have any question on this project development. We will be very happy to answer you ! | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,2 @@ | ||
source 'https://rubygems.org' | ||
gem 'rails', '3.1.0' | ||
gem 'sass-rails' | ||
gem 'sass' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,99 +1,21 @@ | ||
GEM | ||
remote: https://rubygems.org/ | ||
specs: | ||
actionmailer (3.1.0) | ||
actionpack (= 3.1.0) | ||
mail (~> 2.3.0) | ||
actionpack (3.1.0) | ||
activemodel (= 3.1.0) | ||
activesupport (= 3.1.0) | ||
builder (~> 3.0.0) | ||
erubis (~> 2.7.0) | ||
i18n (~> 0.6) | ||
rack (~> 1.3.2) | ||
rack-cache (~> 1.0.3) | ||
rack-mount (~> 0.8.2) | ||
rack-test (~> 0.6.1) | ||
sprockets (~> 2.0.0) | ||
activemodel (3.1.0) | ||
activesupport (= 3.1.0) | ||
bcrypt-ruby (~> 3.0.0) | ||
builder (~> 3.0.0) | ||
i18n (~> 0.6) | ||
activerecord (3.1.0) | ||
activemodel (= 3.1.0) | ||
activesupport (= 3.1.0) | ||
arel (~> 2.2.1) | ||
tzinfo (~> 0.3.29) | ||
activeresource (3.1.0) | ||
activemodel (= 3.1.0) | ||
activesupport (= 3.1.0) | ||
activesupport (3.1.0) | ||
multi_json (~> 1.0) | ||
arel (2.2.3) | ||
bcrypt-ruby (3.0.1) | ||
builder (3.0.4) | ||
erubis (2.7.0) | ||
hike (1.2.3) | ||
i18n (0.7.0) | ||
json (1.8.6) | ||
mail (2.3.3) | ||
i18n (>= 0.4.0) | ||
mime-types (~> 1.16) | ||
treetop (~> 1.4.8) | ||
mime-types (1.25.1) | ||
multi_json (1.12.1) | ||
polyglot (0.3.5) | ||
rack (1.3.10) | ||
rack-cache (1.0.3) | ||
rack (>= 0.4) | ||
rack-mount (0.8.3) | ||
rack (>= 1.0.0) | ||
rack-ssl (1.3.4) | ||
rack | ||
rack-test (0.6.3) | ||
rack (>= 1.0) | ||
rails (3.1.0) | ||
actionmailer (= 3.1.0) | ||
actionpack (= 3.1.0) | ||
activerecord (= 3.1.0) | ||
activeresource (= 3.1.0) | ||
activesupport (= 3.1.0) | ||
bundler (~> 1.0) | ||
railties (= 3.1.0) | ||
railties (3.1.0) | ||
actionpack (= 3.1.0) | ||
activesupport (= 3.1.0) | ||
rack-ssl (~> 1.3.2) | ||
rake (>= 0.8.7) | ||
rdoc (~> 3.4) | ||
thor (~> 0.14.6) | ||
rake (12.0.0) | ||
rdoc (3.12.2) | ||
json (~> 1.4) | ||
sass (3.4.23) | ||
sass-rails (3.1.7) | ||
actionpack (~> 3.1.0) | ||
railties (~> 3.1.0) | ||
sass (>= 3.1.10) | ||
tilt (~> 1.3.2) | ||
sprockets (2.0.5) | ||
hike (~> 1.2) | ||
rack (~> 1.0) | ||
tilt (~> 1.1, != 1.3.0) | ||
thor (0.14.6) | ||
tilt (1.3.7) | ||
treetop (1.4.15) | ||
polyglot | ||
polyglot (>= 0.3.1) | ||
tzinfo (0.3.52) | ||
ffi (1.9.18) | ||
rb-fsevent (0.10.2) | ||
rb-inotify (0.9.10) | ||
ffi (>= 0.5.0, < 2) | ||
sass (3.5.1) | ||
sass-listen (~> 4.0.0) | ||
sass-listen (4.0.0) | ||
rb-fsevent (~> 0.9, >= 0.9.4) | ||
rb-inotify (~> 0.9, >= 0.9.7) | ||
|
||
PLATFORMS | ||
ruby | ||
|
||
DEPENDENCIES | ||
rails (= 3.1.0) | ||
sass-rails | ||
sass | ||
|
||
BUNDLED WITH | ||
1.14.3 | ||
1.15.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
default_app_config = 'members.accounts.app.AccountConfig' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,6 @@ | |
|
||
class AccountsConfig(AppConfig): | ||
name = 'accounts' | ||
|
||
def ready(self): | ||
from . import signals # noqa |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
# Codecs and translitcodec are needed when calling encode() methods | ||
import codecs # noqa | ||
import ldap | ||
import ldap.modlist as modlist | ||
import translitcodec # noqa | ||
|
||
from django.conf import settings | ||
|
||
from .connection.generic import LDAPGenericConnection | ||
from .connection.LDAPManager import LDAPManagerConnection | ||
from .utils import generate_crypt_password | ||
|
||
|
||
class LDAPAccountAdder: | ||
"""Allow the insertion of new accounts in an LDAP directory using the standard POSIX user scheme.""" | ||
|
||
def __init__(self, connection=None): | ||
if connection: | ||
self.__connection = connection | ||
else: | ||
self.__connection = LDAPManagerConnection() | ||
|
||
def build_account_attributes(self, user, password): | ||
""" | ||
Generate an account attributes dict that can be used in LDAP addModList. | ||
Also ensure that the account attributes are correctly formatted, and generate a password hash. | ||
""" | ||
attrs = {} | ||
attrs['cn'] = '{} {}'.format(user.first_name, user.last_name) | ||
attrs['uid'] = user.username | ||
attrs['givenName'] = user.first_name | ||
attrs['sn'] = user.last_name | ||
attrs['uidNumber'] = self.get_biggest_LDAP_uid() + 1 | ||
attrs['gidNumber'] = settings.LDAP_DEFAULT_GID | ||
attrs['userPassword'] = generate_crypt_password(password) | ||
attrs['mail'] = user.email | ||
attrs['homeDirectory'] = (settings.LDAP_DEFAULT_HOME_PATH + user.username) | ||
|
||
# Make sure that every attribute is a ascii string | ||
for key, value in attrs.items(): | ||
attrs[key] = str(value).encode('translit/one/ascii', 'replace') | ||
|
||
attrs['objectclass'] = [ | ||
('inetOrgPerson').encode('translit/one/ascii', 'replace'), | ||
('posixAccount').encode('translit/one/ascii', 'replace'), | ||
('top').encode('translit/one/ascii', 'replace')] | ||
|
||
return attrs | ||
|
||
def get_biggest_LDAP_uid(self): | ||
"""Get the biggest currently registered LDAP UID.""" | ||
search_filter = '(objectClass=posixAccount)' | ||
search_attribute = ["uidNumber"] | ||
search_scope = ldap.SCOPE_SUBTREE | ||
|
||
result_id = self.__connection.search( | ||
settings.LDAP_USERS_BASE_DN, | ||
search_scope, | ||
search_filter, | ||
search_attribute) | ||
|
||
max_uid = 0 | ||
|
||
while 1: | ||
try: | ||
result_type, result_data = self.__connection.result(result_id, 0) | ||
except ldap.NO_SUCH_OBJECT: | ||
raise ldap.LDAPError( | ||
'Distinguished name ({}) does not exist.'.format( | ||
settings.LDAP_USERS_BASE_DN)) | ||
|
||
if result_type == ldap.RES_SEARCH_ENTRY: | ||
try: | ||
uid = int(result_data[0][1]['uidNumber'][0]) | ||
if uid > max_uid: | ||
max_uid = uid | ||
except: | ||
pass | ||
else: | ||
break | ||
|
||
return max_uid | ||
|
||
def test_unique(self, user_id, user_cn): | ||
""" | ||
Test if the given user common name or user ID is already present in the LDAP directory. | ||
Return True if no such user can be found in the directory. | ||
""" | ||
|
||
# As we create a byte string, we can't use format() here | ||
query_string = b''.join([b'(|(cn=', user_cn, b')(uid=', user_id, b'))']) | ||
|
||
results = self.__connection.search_s( | ||
settings.LDAP_USERS_BASE_DN, | ||
ldap.SCOPE_SUBTREE, | ||
query_string.decode('utf-8')) | ||
|
||
return (len(results) == 0) | ||
|
||
def add(self, pending_user, password): | ||
""" | ||
Add the given user to the current LDAP directory. | ||
If an account having the same user name as the one of the pending_user, no action will be taken. | ||
Return True if the user has been successfully added. | ||
""" | ||
attrs = self.build_account_attributes(pending_user, password) | ||
|
||
if self.test_unique(attrs['uid'], attrs['cn']): | ||
dn = 'cn={} {},{}'.format( | ||
pending_user.first_name.encode( | ||
'translit/one/ascii', | ||
'replace').decode(), | ||
pending_user.last_name.encode( | ||
'translit/one/ascii', | ||
'replace').decode(), | ||
settings.LDAP_USERS_BASE_DN) | ||
|
||
ldif = modlist.addModlist(attrs) | ||
|
||
try: | ||
self.__connection.add_s(dn, ldif) | ||
return True | ||
except: | ||
return False | ||
else: | ||
return False | ||
|
||
|
||
class LDAPAccountUpdater: | ||
"""Perform generic actions on a given LDAP account.""" | ||
|
||
def __init__(self, user_dn): | ||
self.__user_dn = user_dn | ||
|
||
def change_password(self, old_password, new_password, connection=None): | ||
""" | ||
Update the password of a given user. | ||
If no LDAP connection is provided, the user old password will be used in a simple bind action. | ||
This allows to check if the user's old password is the correct one. | ||
Returns True if the password has correctly been updated. | ||
""" | ||
|
||
try: | ||
connection = LDAPGenericConnection( | ||
settings.LDAP_SERVER_URI, | ||
self.__user_dn, | ||
old_password, | ||
connection) | ||
except (NameError, ldap.LDAPError): | ||
return False | ||
|
||
new_crypt_password = generate_crypt_password(new_password) | ||
mod_attrs = [( | ||
ldap.MOD_REPLACE, | ||
'userPassword', | ||
[str(new_crypt_password).encode('ascii', 'ignore')] | ||
)] | ||
connection.modify_s(self.__user_dn, mod_attrs) | ||
return True |
Oops, something went wrong.