we are implementing a web service for a Drupal 7 site (the web service code is not part of drupal installation folder).
one of the web services needs to sign up the user on the site.
the main hurdle was getting a hashed password that Drupal will also recognize.
for that , am following a suggestion made on stack overflow to Implement a REST service inside drupal and call that from the outside service code . (that part also seems possible and achieveable).
have implemented a password hashing service with following code:
function GetHashedPassword($string)
{
require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
$hashedpw = user_hash_password($string);
$data = array(
'password' => $hashedpw
);
header("Access-Control-Allow-Origin: *");
drupal_json_output($data);
drupal_exit();
}
the main issue now is that whenever this service is called even with same string , it returns a new hashed value each time..
kindly assist if what we need is actually even possible and if so, then what could be fixed in the above code
any help appreciated
The Drupal user_hash_password function generates a new salt each time it calculates the hash. This will cause a new hash to be generated since the salt is likely to be different to the last one.
Related
I'm stuck with PHP 5.4 and a single database userid because of defects in Comcast's business hosting implementation. The userid problem means that the same credentials I use to manage a MySQL database must also be used while handling requests from ordinary users. I have control over who can login as an ordinary user by delegating the creation of ids to a group of trusted users who will communicate to the ultimate end users the URL they will need to login to the app. And, although the server is running Apache, it ignores an Authorization header.
Positing that some hacker might defeat the HostWays Unix server's file system protection and read all of my PHP source code, I need to avoid having the database credentials appear in the MySQL connect calls in my PHP source. I've come up with the following scheme for encrypting the database credentials, and I want to be sure that the scheme will actually be effective.
I will define a global variable named $credentials in a configuration file. I'll generate the value in my development environment with this code:
$cipher = "AES-128-CBC";
$secretkey = …; // it's a secret!
$secret = openssl_encrypt("$dbuser:$dbpass", $cipher, $secretkey);
Remember, I'm stuck with PHP 5.4, and I wasn't able to get past mysterious errors in openssl_decrypt when I used an initial-value in the encrypt/decrypt calls. Anyhow, this much of the code at least works.
My PHP app can be accessed two ways: one is via an XML payload in a POST transaction coming from a C++ desktop app; the other is via an ordinary URL in a GET. Both methods will use HTTPS. The XML schema calls for an authentication parameter that supplies the $secretkey.
The URL for the GET transaction will be used by general users from a browser. It will include a secret= parameter that encodes both the user's login id and the $secretkey. I will generate the secret= parameter during the transaction that adds the user to the list of authorized users:
$cipher = "AES-128-CBC";
$key = "Fortune42Cookies!";
$secret = openssl_encrypt("$username:$secretkey", $cipher, $key);
In this code, the $secretkey is left over from when the trusted user who is adding this end user to the list logged in. The corresponding decryption code used when the end user logs in is as follows:
$cipher = "AES-128-CBC";
$key = "Fortune42Cookies!";
$clearsecret = explode(":", openssl_decrypt($secret, $cipher, $key));
$username = $clearsecret[0];
$secretkey = $clearsecret[1];
$this->db = new mydatabase($secretkey);
. . .
class mydatabase extends mysqli {
public function __construct($secretkey) {
public $credentials; // set by the configuration script
$cipher = "AES-128-CBC";
$cred = explode(":", openssl_decrypt($credentials, $cipher, $secretkey);
parent::__construct(<database path>, $cred[0], $cred[1], <dbname>);
}
}
To summarize, the __construct call uses $credentials that are stored in encrypted form in a configuration file that my putative hacker can read. We decrypt them using the $secretkey that comes to us either in a secure XML packet or in the URL for a secure GET transaction.
The one flaw I see in this scheme is that a hacker who learns the login id of a registered user and who reads the PHP source code to learn the silly Fortune42Cookies! key could construct that user's unique $secret and thereby impersonate the user. Because there's only one set of credentials for the database, the hacker would then have the keys to the city.
Still, the extra layer of protection (hacker needs to defeat the UNIX file system protection AND learn the name of a real end user) seems worth it.
Fifty years of software development experience tells me I've missed something major. What is it?
In laravel for registration I'm using encrypt algorithm for password instead of inbuilt bcrypt function in Laravel because to get password and send it to mail when password is forgot.
But decrypt it is showing a error like
DecryptException The MAC is invalid in Encrypter.php (line 184)
This , when I run this code it is working on local but server itself it is not working below i have mentioned the code , can anyone please help
public function forgotpassword(Request $request)
{
$email=$request->email;
$selectemail = User::select('email','password','name')
->where('email',$email)
->first();
if($selectemail)
{
$password=decrypt($selectemail->password);
$data = array( 'email' => $selectemail->email,'password' => $password , 'name' => $selectemail->name);
Mail::send('email.resetpassword',$data,function($message) use ($email)
{
$message->to([$email])->subject('Forgot Password Letgo');
});
echo "Mail has sent successfully";
} else {
echo "This email is not yet registered";
}
}
The problem is you generated a new APP_KEY, then if you try to decrypt the old encrypted data it will show the DecryptException: The MAC is invalid.
If you want to decrypt the old data you need to restore your old APP_KEY.
After realizing that, now, adding a new problem there, if you stored new data with another APP_KEY or another encryption method you have a problem on the data because they are mixed on the table.
In case you don't know when do you started with the new encrypt method or differentiate the new encrypted entries, the fastest solution would be reset all the passwords with the new encrypt method.
You can learn more about how Laravel encryption works on the official Laravel docs.
I copied the APP_KEY from the environment it was working dev to the production and the issue was solved. you may want to try it.
In case none of the above helped you, as it was in my case, well, some people mention clearing the cookies, sadly that is ambiguous to say the least.
I tried everything from the above, clear cache in laravel and the browser, hard reload and all..With no success!
SOLUTION: just CLOSE the browser entirely, and reopen it. In my case, I was using both Chrome and Opera, and they were both messing up. I had to close them BOTH, then reopen them for the MAC problem to disappear.
To avoid this, use a custom key instead. The default key is APP_KEY, but you can provide one so your decrypt is not linked with new or old APP_KEY.
I use the following code to resolve it, and it worked in different APP_KEYs.
function customCrypt($vWord){
$customKey = "blabla_key_with_correct_length";
$newEncrypter = new \Illuminate\Encryption\Encrypter( $customKey, Config::get( 'app.cipher' ) );
return $newEncrypter->encrypt( $vWord );
}
function customDecrypt($vWord){
$customKey = "blabla_key_with_correct_length";
$newEncrypter = new \Illuminate\Encryption\Encrypter( $customKey, Config::get( 'app.cipher' ) );
return $newEncrypter->decrypt( $vWord );
}
Important for key length : if $cipher == 'AES-128-CBC' use $length === 16, if $cipher == 'AES-256-CBC' use $length === 32). Check in config/app.cipher which cipher your app uses.
If you run multiple project and passes one encryption key to another project, Just make sure you have made same APP_KEY to your both project.
App key matters in encryption and decryption. I was having 2 sub
domains with different projects in which I was encrypting value on sub
domain and 1 and trying to decrypt on sub domain 2. Issue was resolved
when both projects were having same appkey. Note: No projects should
have same appkey!!!
If you have imported DB form one environment to another, most likely you will face this error. Its recommended to have same APP_KEY as data source application in order to fix bug.
If you have run 2 different Laravel applications locally in the same browser, cookies can be saved in your browser. Please clear the cache and cookies before loading the 2n app.
I'm currently working on a REST client in PHP using Zend Framework and ran into a problem.
I currently have two dummy services that I'm testing with; one is 'noauth' which requires no authentication and just returns some JSON, the other is 'auth' which required authentication and returns more specific JSON. Accessing both directly from the web works without a problem, for example navigating to 'https://example.org/example/dummy/noauth' displays the JSON on the webpage and 'https://example.org/example/dummy/auth' displays a dialog box asking for the user to log in.
My goal is to be able to access those different services from my main web application. The first thing that is required is for the user to log on to this web app. Then they'll be able to call the different services from that web application. I was able to get the noauth working quite easily using this:
$base_url = 'https://example.org';
$client = new Zend_Rest_Client($base_url);
$endpoint = '/example/dummy/noauth';
$response = $client->restGet($endpoint);
But I am unable to get the 'auth' one working without it asking for the user's username and password every time. Currently, I'm using hard coded values for this, but eventually, it'll be the values that the user used to log in that are stored in the session. Here are some of the things I've tried:
$user = base64_encode('username:password');
$client->setHeaders('Authorization: Basic '.$user);
And also:
$client = new Zend_Http_Client();
$client->setAuth('username', 'password', Zend_Http_Client::AUTH_BASIC);
None of these seem to be working. Does anyone have any ideas on how to achieve what I need?
You have to call the getHttpClient() on the REST object, and then call the function you need that's normally in the Zend_Http_Client() after that.
Here's a quick example:
$client = new Zend_Rest_Client($base_url);
$client->getHttpClient()->setAuth($username, $password, Zend_Http_Client::AUTH_BASIC);
...
By doing this, it'll use the username and password in the variables not ask the user every time they want to access the page.
I'm migrating a system from OpenCart to Spree in ruby, and as part of that I would like to seamlessly migrate the users so they can keep login in without changing their passwords.
Looking at the OpenCart code I've found the login function for the website. I'm not great at PHP, so I'm trying to understand how to reproduce the following in ruby
SHA1(CONCAT(salt, SHA1(CONCAT(salt, SHA1('" . $this->db->escape($password) . "')))))
I've tried the following, with no success:
Digest::SHA1.hexdigest("#{salt}#{Digest::SHA1.hexdigest("#{salt}#{Digest::SHA1.hexdigest(" . #{password . ")}")}")
My current test case is:
Password: 7fe391813e
Salt: e4e91e33a
OpenCart hash (what I'm trying to get): 2e62a3b86da5ce878895bcc5745725493bde7ef0
Has anyone done the same migration before? Or can someone explain what the PHP code is actually doing?
Thanks!
The OpenCart code is a MySQL statement, PHP is used only to construct it. You were close with your Ruby alternative, the problem was in password inclusion, dots are used only in PHP. Here is the correct one:
Digest::SHA1.hexdigest("#{salt}#{Digest::SHA1.hexdigest("#{salt}#{Digest::SHA1.hexdigest(password)}")}")
irb(main):001:0> password = "7fe391813e"
=> "7fe391813e"
irb(main):002:0> salt = "e4e91e33a"
=> "e4e91e33a"
irb(main):005:0> Digest::SHA1.hexdigest("#{salt}#{Digest::SHA1.hexdigest("#{salt}#{Digest::SHA1.hexdigest(password)}")}")
=> "2e62a3b86da5ce878895bcc5745725493bde7ef0"
I am new to using WSDL's. I have used REST before but not this. I am trying to run the sample code file that is included on the UPS developer site. Page 23 of this guide is the API I am using. The file you can download includes like ten guides which I have perused, but I just initally want to figure out how to fill out the top configuration part below (I am using php example code file SoapRateClient.php). What do I put for WSDL? What do I put for end point url? The file you download on their site has several wsdl files and I'm not sure which one I am supposed to choose. Guidance appreciated.
<?php
//Configuration
$access = "secret";//I have this no problem
$userid = "";//I have this as well
$passwd = "";//I have this
$wsdl = " Add Wsdl File Here ";//What the heck do I put here!?
$operation = "ProcessRate";
$endpointurl = ' Add URL Here';//Also what do I put here?
$outputFileName = "XOLTResult.xml";
For anyone else out there confused on how to get started with the UPS Rate API, I implemented Jonathan Kelly's UPS Rate API class that he created. You just fill in your account number, key, username, password, and play with the other variables. I was able to return a dollar amount for ground shipping in five minutes. Thank gosh I didn't have to mess with SOAP and web services.
Here is details of top parameters for "SoapRateClient.php"
$access = "xxxx";
It is provided by the UPS.for this you have to create your account at UPS.This account is different from creating online account at the website.
https://www.ups.com/upsdeveloperkit
click on "Step 5: Request an access key."
2 $userid = "xxx";
userid of account.
3 $passwd = "xxx";
password of account
4 $wsdl = "wsdl/RateWS.wsdl";
this is the wsdl file you need to include for "SoapRateClient.php". Here change the path accordingly.
5 $operation = "ProcessRate";
value of operation to perform.
6
$endpointurl = 'https://wwwcie.ups.com/webservices/Rate';
I wish you the best of luck. When I started down this path I ended up grabbing code from several commerce products written in PHP to see how they did it as I could not get the UPS examples to work. Turns out most of them are just doing a POST and manually assembling the XML instead of using SOAP, since it's so painful.
But, regardless, what it wants in $wsdl is the wsdl file location.
End point url is the UPS url for the service you wish to use, for example, for TimeInTransit:
For prod: https://wwwcie.ups.com/ups.app/xml/TimeInTransit
For test: https://onlinetools.ups.com/ups.app/xml/TimeInTransit
EDIT: It appears that the urls above are incorrect. Reference: https://developerkitcommunity.ups.com/index.php/Special:AWCforum/st/id267
Once your testing is completed please direct your Shipping Package XML to the Production
URL:
https://onlinetools.ups.com/webservices/Ship
They should read:
For test: https://wwwcie.ups.com/ups.app/xml/TimeInTransit
For prod: https://onlinetools.ups.com/ups.app/xml/TimeInTransit