-
Notifications
You must be signed in to change notification settings - Fork 5
Docker based examples #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 2 commits
217f3aa
c7cdf66
00d361d
bc2c212
3591f2d
4cd6f92
36c3861
9eb0204
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
[package] | ||
name = "openldap" | ||
version = "1.2.2" | ||
authors = ["Josh Leverette <[email protected]>", "Ross Delinger <[email protected]>", "Stephen Holsapple <[email protected]>", "Yong Wen Chua <[email protected]>"] | ||
authors = ["Josh Leverette <[email protected]>", "Ross Delinger <[email protected]>", "Stephen Holsapple <[email protected]>", "Yong Wen Chua <[email protected]>", "Mathias Myrland <[email protected]>"] | ||
license = "MIT" | ||
readme = "README.md" | ||
repository = "https://github.com/coder543/rust-cldap" | ||
|
@@ -11,3 +11,8 @@ description = "Straightforward Rust bindings to the C openldap library. This is | |
|
||
[dependencies] | ||
libc = "0.2.10" | ||
|
||
[workspace] | ||
members = [ | ||
"examples/simple_bind_authentication" | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# Simple Bind with start_tls | ||
|
||
This example shows how to use simple_bind in combination with start_tls | ||
and a manager account to do a typical user authentication lookup. | ||
|
||
Start TLS is the recommended way to do secure LDAP; ldaps:// on port 636 is deprecated. | ||
|
||
## Running | ||
|
||
Start the example docker using the start_example_server.sh script from | ||
the examples directory. Then, from the simple_bind directory, do | ||
|
||
```shell script | ||
cargo run -- -u fry -p fry | ||
``` | ||
|
||
## Steps that are being performed | ||
|
||
The first step is to set up the LDAPRust instance, and perform start_tls on it. | ||
This ensures that our communication is encrypted. Note that we are not verifying | ||
the server certificate in this example; this is something you should do in production. | ||
|
||
The next step is to simple_bind using our manger accounts DN and password. This | ||
will allow us to perform an ldap_search later on. | ||
|
||
Now, we take the incoming user name string, and perform an ldap_search for it. | ||
Note how we are matching either email or username. Our search yields the DN | ||
for the provided credentials. | ||
|
||
The last step is to attempt a simple bind with the discovered DN and provided | ||
user password. If all goes well, we are authenticated, otherwise, something | ||
went wrong. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
#[macro_use] | ||
extern crate clap; | ||
|
||
extern crate openldap; | ||
|
||
use openldap::errors::*; | ||
use openldap::*; | ||
use std::ptr; | ||
|
||
#[derive(Clap)] | ||
#[clap( | ||
name = "LDAP simple_bind_authentication with start_tls authentication example", | ||
author = "Mathias Myrland <[email protected]>", | ||
version = "0.1.0" | ||
)] | ||
struct AuthOpts { | ||
#[clap(short = "u")] | ||
user: String, | ||
|
||
#[clap(short = "p")] | ||
password: String, | ||
} | ||
|
||
fn ldap_with_start_tls(ldap_uri: &str) -> Result<RustLDAP, LDAPError> { | ||
let ldap = RustLDAP::new(ldap_uri).unwrap(); | ||
|
||
ldap.set_option( | ||
codes::options::LDAP_OPT_PROTOCOL_VERSION, | ||
&codes::versions::LDAP_VERSION3, | ||
); | ||
|
||
// WARNING: Normally you would want to verify the server certificate to avoid | ||
// man in the middle attacks, but for this testing scenario we're using a | ||
// generated self signed certificate from the docker container. | ||
// | ||
// To set up certificate validation, use the LDAP_OPT_X_TLS_CACERT* options | ||
ldap.set_option( | ||
codes::options::LDAP_OPT_X_TLS_REQUIRE_CERT, | ||
&codes::options::LDAP_OPT_X_TLS_NEVER, | ||
); | ||
|
||
ldap.set_option(openldap::codes::options::LDAP_OPT_X_TLS_NEWCTX, &0); | ||
|
||
ldap.start_tls(None, None)?; | ||
|
||
Ok(ldap) | ||
} | ||
|
||
fn do_simple_bind( | ||
ldap: &RustLDAP, | ||
ldap_manager_user: &str, | ||
ldap_manager_pass: &str, | ||
) -> Result<(), LDAPError> { | ||
let bind_result = ldap.simple_bind(ldap_manager_user, ldap_manager_pass)?; | ||
|
||
match bind_result { | ||
v if v == openldap::codes::results::LDAP_SUCCESS => Ok(()), | ||
_ => Err(LDAPError::from(String::from( | ||
"Authentication with simple bind failed", | ||
))), | ||
} | ||
} | ||
|
||
fn ldap_dn_lookup(ldap: &RustLDAP, who: &str) -> Result<String, LDAPError> { | ||
// Show all DNs matching the description "Human" | ||
// ldap_search is a powerful query language, look at | ||
// https://confluence.atlassian.com/kb/how-to-write-ldap-search-filters-792496933.html | ||
// for an overview | ||
// | ||
// This particular filter allows the user to sign in with either | ||
// uid or email | ||
let filter = format!("(|(uid={})(mail={}))", who, who); | ||
|
||
match ldap.ldap_search( | ||
"ou=people,dc=planetexpress,dc=com", | ||
codes::scopes::LDAP_SCOPE_SUBTREE, | ||
Some(filter.as_str()), | ||
Some(vec!["dn"]), | ||
true, | ||
None, | ||
None, | ||
ptr::null_mut(), | ||
-1, | ||
) { | ||
Ok(search_results) => { | ||
for result_map in search_results { | ||
for result_tuple in result_map { | ||
println!("Found result map with key {}", result_tuple.0); | ||
for result_data in result_tuple.1 { | ||
println!("\t {}", result_data); | ||
return Ok(result_data); | ||
} | ||
} | ||
} | ||
|
||
Err(LDAPError::from(String::from( | ||
"Authentication with simple bind failed", | ||
))) | ||
} | ||
_ => Err(LDAPError::from(String::from( | ||
"Authentication with simple bind failed", | ||
))), | ||
} | ||
} | ||
|
||
fn main() { | ||
let options = AuthOpts::parse(); | ||
let user_to_authenticate = options.user; | ||
let pwd_to_authenticate = options.password; | ||
|
||
let ldap_uri = "ldap://localhost:389"; | ||
let ldap_manager_dn = "cn=Hubert J. Farnsworth,ou=people,dc=planetexpress,dc=com"; | ||
let ldap_manager_pass = "professor"; | ||
|
||
let ldap = ldap_with_start_tls(ldap_uri).unwrap(); | ||
|
||
// Bind to the LDAP server with the manager account, | ||
// this is done to perform a search for the DN to | ||
// use when authenticating the user attempting to | ||
// sign in. Obviously, the manager credentials should | ||
// be kept secret, and not be put under version control. | ||
// In our test scenario, the professor is the manager. | ||
do_simple_bind(&ldap, ldap_manager_dn, ldap_manager_pass).unwrap(); | ||
|
||
if let Ok(fry_dn) = ldap_dn_lookup(&ldap, user_to_authenticate.as_str()) { | ||
// Now, perform a bind with the DN we found matching the user attempting to sign in | ||
// and the password provided in the authentication request | ||
do_simple_bind(&ldap, fry_dn.as_str(), pwd_to_authenticate.as_str()).unwrap(); | ||
|
||
println!("Successfully signed in as fry"); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is vulnerable to a timing side-channel attack. An attacker that does not have a valid set of credentials should not be able to learn which user accounts exist. However, if the attacker tries to authenticate with a bunch of credentials, they may notice that certain authentication attempts take longer than others. That's because the second simple-bind is only performed if Since this is a very common problem with authentication code, the example should demonstrate how to do it more safely. The basic idea is that you do the second simple-bind even if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch! I'll see if I get time to update the example this weekend! |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#! /usr/bin/env bash | ||
|
||
docker run -p 389:389 -p 636:636 rroemhild/test-openldap |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is vulnerable to LDAP injection. It's actually a problem of the library since it does not provide the proper tools for escaping, so I opened #9 to track this issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don’t think the C LDAP library provided this functionality, and since this is a thin wrapper around it it was never present. The C library likely assumed that you escaped your queries yourself, as I did when I was using it for the project the fork was made for.
That being said, I do not think it’s a bad idea to add that ability if there is a standardized way to perform it and it is not required to be done if you can prove that your queries are otherwise ‘safe’.