Merge branch 'hotfix/prevent_ldap_injection' into 'master'

Hotfix/prevent ldap injection

Closes #150

See merge request !188
This commit is contained in:
Martin Pepin 2017-03-20 23:06:59 +01:00
commit ae38b5d1e7
8 changed files with 52 additions and 35 deletions

View file

@ -56,22 +56,24 @@ def autocomplete(request):
# Fetching data from the SPI # Fetching data from the SPI
if hasattr(settings, 'LDAP_SERVER_URL'): if hasattr(settings, 'LDAP_SERVER_URL'):
# Fetching # Fetching
ldap_query = '(|{:s})'.format(''.join( ldap_query = '(&{:s})'.format(''.join(
['(cn=*{bit:s}*)(uid=*{bit:s}*)'.format(**{"bit": bit}) '(|(cn=*{bit:s}*)(uid=*{bit:s}*))'.format(bit=bit)
for bit in bits] for bit in bits if bit.isalnum()
)) ))
with Connection(settings.LDAP_SERVER_URL) as conn: if ldap_query != "(&)":
conn.search( # If none of the bits were legal, we do not perform the query
'dc=spi,dc=ens,dc=fr', ldap_query, with Connection(settings.LDAP_SERVER_URL) as conn:
attributes=['uid', 'cn'] conn.search(
) 'dc=spi,dc=ens,dc=fr', ldap_query,
queries['clippers'] = conn.entries attributes=['uid', 'cn']
# Clearing redundancies )
queries['clippers'] = [ queries['clippers'] = conn.entries
Clipper(clipper.uid, clipper.cn) # Clearing redundancies
for clipper in queries['clippers'] queries['clippers'] = [
if str(clipper.uid) not in usernames Clipper(clipper.uid, clipper.cn)
] for clipper in queries['clippers']
if str(clipper.uid) not in usernames
]
# Resulting data # Resulting data
data.update(queries) data.update(queries)

View file

@ -800,7 +800,7 @@ input#search_autocomplete {
height: 40px; height: 40px;
padding: 10px 8px; padding: 10px 8px;
margin: 0 auto; margin: 0 auto;
margin-top: 20px; margin-top: 0px;
display: block; display: block;
color: #aaa; color: #aaa;
} }
@ -1119,3 +1119,10 @@ div.messages div.alert-success div.container {
div.messages div.alert div.container a { div.messages div.alert div.container a {
color: inherit; color: inherit;
} }
/* Help text */
p.help-block {
margin: 5px auto;
width: 90%;
}

View file

@ -9,7 +9,9 @@
{% block realcontent %} {% block realcontent %}
<h2>Inscription d'un nouveau membre</h2> <h2>Inscription d'un nouveau membre</h2>
<input type="text" name="q" id="search_autocomplete" spellcheck="false" /> <p class="help-block">Les mots contenant des caractères non alphanumériques seront ignorés</p>
<input type="text" name="q" id="search_autocomplete" spellcheck="false"
placeholder="Chercher un utilisateur par nom, prénom ou identifiant clipper" />
<div id="form-placeholder"></div> <div id="form-placeholder"></div>
<div class="yourlabs-autocomplete"></div> <div class="yourlabs-autocomplete"></div>
<script type="text/javascript"> <script type="text/javascript">
@ -20,7 +22,6 @@
minimumCharacters: 3, minimumCharacters: 3,
id: 'search_autocomplete', id: 'search_autocomplete',
choiceSelector: 'li:has(a)', choiceSelector: 'li:has(a)',
placeholder: "Chercher un utilisateur par nom, prénom ou identifiant clipper",
box: $(".yourlabs-autocomplete"), box: $(".yourlabs-autocomplete"),
}); });
$('input#search_autocomplete').bind( $('input#search_autocomplete').bind(

View file

@ -23,7 +23,7 @@ def key(d, key_name):
def highlight_text(text, q): def highlight_text(text, q):
q2 = "|".join(q.split()) q2 = "|".join(re.escape(word) for word in q.split())
pattern = re.compile(r"(?P<filter>%s)" % q2, re.IGNORECASE) pattern = re.compile(r"(?P<filter>%s)" % q2, re.IGNORECASE)
return mark_safe(re.sub(pattern, return mark_safe(re.sub(pattern,
r"<span class='highlight'>\g<filter></span>", r"<span class='highlight'>\g<filter></span>",

View file

@ -75,22 +75,24 @@ def account_create(request):
# Fetching data from the SPI # Fetching data from the SPI
if hasattr(settings, 'LDAP_SERVER_URL'): if hasattr(settings, 'LDAP_SERVER_URL'):
# Fetching # Fetching
ldap_query = '(|{:s})'.format(''.join( ldap_query = '(&{:s})'.format(''.join(
['(cn=*{bit:s}*)(uid=*{bit:s}*)'.format(bit=word) '(|(cn=*{bit:s}*)(uid=*{bit:s}*))'.format(bit=word)
for word in search_words] for word in search_words if word.isalnum()
)) ))
with Connection(settings.LDAP_SERVER_URL) as conn: if ldap_query != "(&)":
conn.search( # If none of the bits were legal, we do not perform the query
'dc=spi,dc=ens,dc=fr', ldap_query, with Connection(settings.LDAP_SERVER_URL) as conn:
attributes=['uid', 'cn'] conn.search(
) 'dc=spi,dc=ens,dc=fr', ldap_query,
queries['clippers'] = conn.entries attributes=['uid', 'cn']
# Clearing redundancies )
queries['clippers'] = [ queries['clippers'] = conn.entries
Clipper(clipper.uid, clipper.cn) # Clearing redundancies
for clipper in queries['clippers'] queries['clippers'] = [
if str(clipper.uid) not in usernames Clipper(clipper.uid, clipper.cn)
] for clipper in queries['clippers']
if str(clipper.uid) not in usernames
]
# Resulting data # Resulting data
data.update(queries) data.update(queries)

View file

@ -341,3 +341,7 @@ textarea {
.help h4 { .help h4 {
margin:15px 0; margin:15px 0;
} }
.help-block {
padding-top: 15px;
}

View file

@ -23,6 +23,7 @@
{{ trigramme_form.trigramme }} {{ trigramme_form.trigramme }}
</div> </div>
<div id="trigramme_valid"></div> <div id="trigramme_valid"></div>
<p class="help-block">Les mots contenant des caractères non alphanumériques seront ignorés</p>
<input type="text" name="q" id="search_autocomplete" spellcheck="false" placeholder="Chercher un utilisateur par nom, prénom ou identifiant clipper" class="form-control"> <input type="text" name="q" id="search_autocomplete" spellcheck="false" placeholder="Chercher un utilisateur par nom, prénom ou identifiant clipper" class="form-control">
<div style="position:relative;"> <div style="position:relative;">
<div id="search_results"></div> <div id="search_results"></div>

View file

@ -11,7 +11,7 @@ register = template.Library()
def highlight_text(text, q): def highlight_text(text, q):
q2 = "|".join(q.split()) q2 = "|".join(re.escape(word) for word in q.split())
pattern = re.compile(r"(?P<filter>%s)" % q2, re.IGNORECASE) pattern = re.compile(r"(?P<filter>%s)" % q2, re.IGNORECASE)
regex = r"<span class='highlight_autocomplete'>\g<filter></span>" regex = r"<span class='highlight_autocomplete'>\g<filter></span>"
return mark_safe(re.sub(pattern, regex, text)) return mark_safe(re.sub(pattern, regex, text))