LDAP Strong(er) authentication required - php

I want to add the value to the attribute. This is my code below.
function set_attribute($attribute, $uid, $service)
{
$entries = $this->get_account($uid);
if ($entries != false && count($entries) == 1) {
$entry = $entries[0];
$result = $entry->add(array($attribute => $service));
if (PEAR::isError($result))
return false;
else {
$result = $entry->update();
if (PEAR::isError($result))
return false;
}
return true;
} else
return false;
}
I failed to add new value to the attribute. This is the error when I dump this code $result->getMessage()
string(121) "Could not add new values to attribute serviceType: Strong(er) authentication required: LDAP_STRONG_AUTH_REQUIRED"
What's wrong with it. I find no solution at all even I have authenticated.

This does not look like confidentiality required error, when you need SSL/TLS enabled to secure the channel rather than a clear text connection. Though you never know, since you do not clarify if your connection is secure or not.
I wonder if this is meant as a permission issue? Or perhaps this is a case where, the system is allowing a clear text bind, but will not allow certain operations without secure comms on the connection.

Related

php function verify token works in localhost but not on GoDaddy server

I have php function that is supposed to verify if there is a token, and if so, display some information. The function works fine when I use xampp in localhost. When I do it in prod on the server, it gives me a 'token undefined' error, even though I can see the token in dev tools. What could possibly be causing the error?
my php function
public function viewCompanies()
{
if (isset($GLOBALS['headers']['Authorization'])) {
print_r($GLOBALS['headers']['Authorization']);
if ($id = $this->VerifyUserToken($GLOBALS['headers']['Authorization'], $_SERVER['REMOTE_ADDR'])) {
$companies = $this->currentModel->viewCompanies();
if ($companies) {
echo json_encode($companies);
} else {
echo json_encode(['success' => false]);
}
}
else {
echo json_encode(['success' => false, 'error' => "invalid token"]);
}
} else {
echo json_encode(['success' => false, 'error' => "token undefined"]);
}
}
the verifyUserToken function
public function verifyUserToken($token, $ip) {
$db = new Database();
$db->query('SELECT * FROM auth WHERE token = :token AND expiry >now()');
$db->bind(':token', $token);
//check database if token exists and is not expired
if($res = $db->single()) {
// checks if token matches to ip address
// returns user or contact id if verified else returns false
if($res->token === $token && $res->ip === $ip) {
$this->cleanTokens();
if($res->user_id >0) {
return $res->user_id;
}
//
} else {
return false;
}
} else {
return false;
}
}
I checked the database, and the token is clearly there
I tested the function on Postman and I get the same token undefined error. Please let me know if there's any other info I should add. I've no idea how to debug this.
in the end. it was goDaddy that saved the day. They sent me the following message, after I opened a ticket and spoke with them:
In regards to the issue you are seeing with custom HTTP headers being stripped out of requests on your site, the issue you are running into is actually due to the CGI handler Apache is configured to use by default on cPanel. The CGI handler, for security reasons, strips out custom header entries that are not explicitly registered within Apache's configuration. We can further verify this by changing the PHP handler the site uses from CGI to PHP-FPM.
If you...please do not hesitate to contact our support teams over the phone or through live chat.
Sincerely,
all's well that ends well.

Joomla PHP API check if user is activated in external authentication script

I have an external Joomla authenticator script, but it turns out that it ignores if the user didn't activate, and it even ignores if the user is blocked.
I've used the following script with some slight modifications, but the basics are the same:
Joomla 3 External authentication script
Here's my code:
...
if ($result)
{
$match = JUserHelper::verifyPassword($credentials['password'], $result->password, $result->id);
if ($match === true)
{
// Bring this in line with the rest of the system
$user = JUser::getInstance($result->id);
//perform the login action
$error = $app->login($credentials);
$logged_user = JFactory::getUser();
if($logged_user->block == 1 && $logged_user->activation) //some kind of check that's not working basically
{
echo $credentials['username'];
}
}
else
{
// Invalid password
die('');
}
} else {
// Invalid user
die('');
}
You can see that I tried playing around with the 'block' and 'activation' properties of the user object (as seen here) but it wasn't working properly.
What is the specific property (or properties) that I have to check, to deduct, whether a user that is trying to sign-in via this script is activated or not?

SSL Over Javascript

I've seen a few similar questions that don't quite seem to address my exact use case, and I THINK I've figured out the answer, but I'm a total noob when it comes to security, RSA, and pretty much everything associated with it. I have a basic familiarity with the concepts, but all of the actual implementations I've done up to this point were all about editing someone else's code rather than generating my own. Anyway, here's where I am:
I know that Javascript is an inherently bad place to do encryption. Someone could Man-in-the-Middle your response and mangle the JS so you'll end up sending unencrypted data over the wire. It SHOULD be done via an HTTPS SSL/TLS connection, but that kind of hosting costs money and so do the official signed certificates that should realistically go with the connection.
That being said, I think the way I'm going to do this circumvents the Man-in-the-Middle weakness of JS encryption by virtue of the fact that I'm only ever encrypting one thing (a password hash) for one RESTful service call and then only using that password hash to sign requests from the client in order to authenticate them as coming from the user the requests claim. This means the JS is only responsible for encrypting a password hash once at user account creation and if the server cannot decode that cipher then it knows it's been had.
I'm also going to save some client information, in particular the $_SERVER['REMOTE_ADDR'] to guarantee that someone doesn't M-i-t-M the registration exchange itself.
I'm using PHP's openssl_pkey_ functions to generate an asymmetric key, and the Cryptico library on the client side. My plan is for the user to send a "pre-registration" request to the REST service, which will cause the server to generate a key, store the private key and the client information in a database indexed by the email address, and then respond with the public key.
The client would then encrypt the user's password hash using the public key and send it to the REST service as another request type to complete the registration. The server would decrypt and save the password hash, invalidate the client information and the private key so no further registrations could be conducted using that information, and then respond with a 200 status code.
To login, a user would type in their email address and password, the password would be hashed as during registration, appended to the a request body, and hashed again to sign a request to a login endpoint which would try to append the stored hash to the request body and hash it to validate the signature against the one in the request and so authenticate the user. Further data requests to the service would follow the same authentication process.
Am I missing any glaring holes? Is is possible to spoof the $_SERVER['REMOTE_ADDR'] value to something specific? I don't need the IP address to be accurate or the same as when the user logs in, I just need to know that the same machine that 'pre-registered' and got a public key followed up and completed the registration instead of a hijacker completing the registration for them using a snooped public key. Of course, I guess if they can do that, they've hijacked the account beyond recovery at creation and the legitimate user wouldn't be able to complete the registration with their own password, which is ok too.
Bottom line, can someone still hack my service unless I fork out for a real SSL host? Did I skirt around Javascript's weaknesses as an encryption tool?
As I write and debug my code, I'll post it here if anyone wants to use it. Please let me know if I'm leaving my site open to any kind of attacks.
These are the functions that validate client requests against the hash in the headers, generate the private key, save it to the database, respond with the public key, and decrypt and check the password hash.
public function validate($requestBody = '',$signature = '',$url = '',$timestamp = '') {
if (is_array($requestBody)) {
if (empty($requestBody['signature'])) { return false; }
if (empty($requestBody['timestamp'])) { return false; }
if ($requestBody['requestBody'] === null) { return false; }
$signature = $requestBody['signature'];
$timestamp = $requestBody['timestamp'];
$requestBody = $requestBody['requestBody'];
}
if (($requestBody === null) || empty($signature) || empty($timestamp)) { return false; }
$user = $this->get();
if (count($user) !== 1 || empty($user)) { return false; }
$user = $user[0];
if ($signature !== md5("{$user['pwHash']}:{$this->primaryKey}:$requestBody:$url:$timestamp")) { return false; }
User::$isAuthenticated = $this->primaryKey;
return $requestBody;
}
public function register($emailAddress = '',$cipher = '') {
if (is_array($emailAddress)) {
if (empty($emailAddress['cipher'])) { return false; }
if (empty($emailAddress['email'])) { return false; }
$cipher = $emailAddress['cipher'];
$emailAddress = $emailAddress['email'];
}
if (empty($emailAddress) || empty($cipher)) { return false; }
$this->primaryKey = $emailAddress;
$user = $this->get();
if (count($user) !== 1 || empty($user)) { return false; }
$user = $user[0];
if (!openssl_private_decrypt(base64_decode($cipher),$user['pwHash'],$user['privateKey'])) { return false; }
if (md5($user['pwHash'].":/api/preRegister") !== $user['session']) { return false; }
$user['session'] = 0;
if ($this->put($user) !== 1) { return false; }
$this->primaryKey = $emailAddress;
User::$isAuthenticated = $this->primaryKey;
return $this->getProfile();
}
public function preRegister($emailAddress = '',$signature = '') {
if (is_array($emailAddress)) {
if (empty($emailAddress['signature'])) { return false; }
if (empty($emailAddress['email'])) { return false; }
$signature = $emailAddress['signature'];
$emailAddress = $emailAddress['email'];
}
if (empty($emailAddress) || empty($signature)) { return false; }
$this->primaryKey = $emailAddress;
$response = $this->makeUserKey($signature);
if (empty($response)) { return false; }
$response['emailAddress'] = $emailAddress;
return $response;
}
private function makeUserKey($signature = '') {
if (empty($signature)) { return false; }
$config = array();
$config['digest_alg'] = 'sha256';
$config['private_key_bits'] = 1024;
$config['private_key_type'] = OPENSSL_KEYTYPE_RSA;
$key = openssl_pkey_new($config);
if (!openssl_pkey_export($key,$privateKey)) { return false; }
if (!$keyDetails = openssl_pkey_get_details($key)) { return false; }
$keyData = array();
$keyData['publicKey'] = $keyDetails['key'];
$keyData['privateKey'] = $privateKey;
$keyData['session'] = $signature;
if (!$this->post($keyData)) { return false; }
$publicKey = openssl_get_publickey($keyData['publicKey']);
$publicKeyHash = md5($keyData['publicKey']);
if (!openssl_sign($publicKeyHash,$signedKey,$privateKey)) { return false; }
if (openssl_verify($publicKeyHash,$signedKey,$publicKey) !== 1) { return false; }
$keyData['signedKey'] = base64_encode($signedKey);
$keyData['rsa'] = base64_encode($keyDetails['rsa']['n']).'|'.bin2hex($keyDetails['rsa']['e']);
unset($keyData['privateKey']);
unset($keyData['session']);
return $keyData;
}
What you are trying to do is to replace the need for SSL certificates signed by a Certificate Authority with custom JavaScript. I'm not a security expert, but as far as I know the simple answer is that this is not possible.
The basic fact is that on the public internet, the server can't trust what a client says, and a client can't trust what the server says, exactly because of man in the middle attacks. The reason why certificate authorities are necessary to begin with is to establish some kind of impartial trust base. CA's are carefully vetted by the browser vendors, and it's the only trust currently available on the public internet, although it's certainly not perfect.
I am curious to know why a relatively inexpensive SSL certificate (like the 1-year from Digicert at $175 USD) is out of the question. Especially if this is for a business, $175/yr is a reasonable expense (it works out to about $12.60 USD/month).

Optimal way to handle "return"?

I need an advice how to handle function with lots of different return's better.
I have this simple log in function in my class:
public function login($email, $password){
$record = // Go to database and find what we need.
if($record){
// Check pass, $user_match = TRUE;
} else {
return 1; //No such user. Please register!
}
$active = (1 == $record['is_active']) ? TRUE : FALSE;
$verified = (1 == $record['is_verified']) ? TRUE : FALSE;
//User email and password matched:
if($user_match == true){
if($verified === true){
// Start session and insert to db table "online_users"
// Check that user was inserted to table: $confirm = $stmt->rowCount();
if($confirm !== 1){
return 2; //Unexpected technical error. Please try again in a moment.
}
return 0; //0 means that all clear, we good to go.
} else {
return 3; //not verified
}
} else {
return 4; // no match with email and pass, reject!
}
}
The problem is, that now all the time I need to check all return's, something like that:
$log = $user->login($_POST['email'], $_POST['pass']);
if($log === 0) {
//Log in & edirect
} elseif ($log === 1) {
//No such user. Tell to register
} elseif($log === 2){
//technical error, try again
} elseif($log === 3){
//Not verified
} elseif($log === 4){
//wrong password
It's really annoying right now, and imagine if I would need to check like 20 return's? Is there any better way? How to do it more efficient and faster?
Thanks in advance.
You should rethink the purpose of this function and structure the return types accordingly. If the purpose is to log the user in, there can only be one answer: it either worked or it didn't. So the primary return type of the function should be a boolean. How to differentiate between different causes for failure is a different topic.
Option 1: throw exceptions:
try {
if (!$foo->login()) {
echo 'Invalid credentials';
}
} catch (UserNotActiveException $e) {
...
} catch (UserNotValidatedException $e) {
...
}
Not necessarily the most elegant option, since a failed login isn't really an exceptional circumstance.
Option 2: save the error state in the login provider:
if (!$foo->login()) {
echo "You're not logged in because ", $foo->loginError();
}
Whether this is good or not depends on how the class is used otherwise, you may not want to make it too stateful.
Option 3: separate the problem of login from what is the user's state entirely:
if (!$foo->login($user)) {
switch ($foo->currentStatus($user)) {
case $foo::ALL_OK :
echo 'Login credentials invalid';
break;
case $foo::ACCOUNT_INACTIVE :
...
}
}
Option 4: return a status object:
$result = $foo->login();
switch ($result->status) {
case $result::ALL_OK :
...
}
That's essentially what you're doing now, just without the magic numbers.
Using exceptions would be one way to provide clear handling of error code, depending on how this fits into the rest of your application.
As was pointed out by Nanne, you shouldn't use exceptions for flow control: they should only indicate exceptional circumstances. The technical error is clearly an exceptional circumstance and using exceptions for this would be clear and appropriate.
Using exceptions for the rest of it is less clear, but still an option. You could simply throw an exception with different error messages for each failure condition, or different exception classes that have appropriate handlers for the failure conditions.
This is starting to break the semantics of exceptions, depending on how this code fits in with the rest. Being able to call the login function elsewhere without having to worry about it throwing inappropriate exceptions might be useful or necessary, for example.
In the end, there's probably no getting around the need to have explicit checks for each of those failing conditions and returning them inside the function. Again, depending on how flexible this needs to be, you could just return true on a successful login, or an error message on failure (using === to verify that the result is true, not just truthy). Or you could return an object with a success property and an error condition, which at least makes your error handling code a matter of checking the success and handling the error code.
If you need significantly different error handling mechanisms for each failure condition, then returning a constant for each failure case could at least make it clear what's going on in the code. You can then return LOGIN_PASSWORDS_DO_NOT_MATCH instead of a cryptic number, which could then be checked in your error code.
Better use switch statement if you need many if-else statements:
$log = $user->login($_POST['email'], $_POST['pass']);
switch ($log) {
case 1:
break;
case 2:
break;
//etc....
}
To clarify error codes use named constants or static array of name=>code pairs instead of "magic numbers"
static $ERROR_CODES = array(
"WRONG_PASSWORD"=>1,
"WRONG_EMAIL"=>2
);
switch ($log) {
case LoginClass::$ERROR_CODES["WRONG_PASSWORD"]:
break;
case LoginClass::$ERROR_CODES["WRONG_EMAIL"]:
break;
//etc....
}
You can use INI Files
write your bugs in an ini file:
1 = "Error"
2 = " Technical"
3 = "Network"
...
And save it into and ini file. Then use this code:
<?php
$array = parse_ini("er.ini");
echo $array[$log];
?>

PHP Digest authentication with MD5

I wrote a class to authenticate a user using HTTP Authentication the Digest way. I read a few articles and I got it working. Now, I would like to let it make use of Md5 passwords, but I can't seem to get it working, this is the function authenticating the users.
public function authenticate() {
// In case the user is not logged in already.
if (empty($_SERVER['PHP_AUTH_DIGEST'])) {
// Return the headers.
$this->show_auth();
} else {
// Parse the given Digest-data.
$data = $this->parse_request($_SERVER['PHP_AUTH_DIGEST']);
// Check the data.
if (!$data) {
// Display an error message.
die($this->unauthorized);
} else {
// Based on the given information, generate the valid response.
$usr_password = "test";
// Generate the response partly.
$A1 = md5($data['username'].":".$this->get_realm().":".$usr_password);
$A2 = md5($_SERVER['REQUEST_METHOD'].":".$data['uri']);
// Generate the valid response.
$val_response = md5($A1.":".$data['nonce'].":".$data['nc'].":".$data['cnonce'].":".$data['qop'].":".$A2);
// Compare the valid response with the given response.
if ($data['response'] != $val_response) {
// Display the login again.
$this->show_auth();
} else {
// Return true.
return true;
}
}
}
}
So imagine the $usr_password="test" will be $usr_password=md5("test");
How do I compare passwords then?
Thanks.
The MD5 function is hashing function, one-directional method to produce the same result for the same input.
Thus, to compare $password1 to $password2 without revealing (comparing directly) both of them it should be enough to compare their hashes:
$hash1 = md5($password1); // hash for pass 1
$hash2 = md5($password2); // hash for pass 2
if ($hash1 === $hash2) {
// here goes the code to support case of passwords being identical
} else {
// here goes the code to support case of passwords not being identical
}
Is it clear enough? Let me know.

Categories