How can I controll what external web site accesses my web service? - php

*I'm trying to find out how the "simplest" form of identification can be achieve in order for my partners website to access my web service to retrieve information.*
I want to make sure that only my partner has access to retrieve this information. There is no sensitive data as the data will be shown on my partners website. But I don't want other websites taking advantage of my web service and retrieve data without having access to do so.
I know I can get the IP address using the HttpRequest object, then do a reverse lookup. But not all websites has dedicated ip address and a ISP may use the same IP Address for multiple websites.
I can't see how passing unique identifiers as parameter in the URL can help, because "anyone" can catch that data and use it themselves. But I will use it as an added check.
So the only "secure" way I come up with, is identifying the website accessing my website, then control this against a list on my server.
I would appreciate feedback on what methods would be "most secure".

It's common practice amongst web services to use public/private keys to authenticate API requests. A few example sites that use them: Google, Twitter, EventBrite, Last.FM, GitHub, etc.
These work by having a public or consumer key which is known to everyone. Then each user is given a private or secret key to allow authentication. The cool thing about using this, is since you know exactly who is making the request you have the ability to track activity and potentially throttle number of requests if abused.

The most secure method is to use SSL channel and ask for authentication. If authentication passes then you can give back to client some sort of session key(which can be randomly generated string) and check it on every request.
If your service don't allow to use SSL, then you can try just adding simple username/password authentication for your partners, but in this case if someone intercept your communication they can access your service with same credentials.
Other way is using signatures on every request. For example you can use GPG for this purpose. Your server is holding public keys of all your partners. When partner wants to make query to your server he just signs his request with his private key and upon receiving you will be able to securely verify that this request was sent by particular partner and it's 100% not forged.
Edit
For GPG you need to install PECL module called gnupg. Here is class from our framework that utilize GPG functionality.
class GPG
{
/**
* Encrypt given data to one or more recipients
*
* #param string $string
* #param string|array $encryptKeyID
* #param bollean $armour
* #return string
*/
public static function encrypt($string, $encryptKeyID, $armour = true){
$gpg = new Crypt_GPG();
if(is_array($encryptKeyID)){
foreach($encryptKeyID as $keyId){
$gpg->addEncryptKey($keyId);
}
}
else{
$gpg->addEncryptKey($encryptKeyID);
}
return $gpg->encrypt($string, $armour);
}
/**
* Decrypt given data
*
* #param string $string
* #param string $keyPassword
* #param string $keyID
* #return string
*/
public static function decrypt($string, $keyID, $keyPassword = null){
$gpg = new Crypt_GPG();
$gpg->addDecryptKey($keyID, $keyPassword);
return $gpg->decrypt($string);
}
/**
* Sign given string
*
* #param string $string
* #param string $keyID
* #param string $keyPassword
* #param boolean $mode
* #param boolean $armor
* #return string
*/
public static function sign($string, $keyID, $keyPassword = null, $mode = null, $armor = true){
$gpg = new Crypt_GPG();
if($mode === null){
$mode = Crypt_GPG::SIGN_MODE_CLEAR;
}
$gpg->addSignKey($keyID, $keyPassword);
return $gpg->sign($string, $mode);
}
/**
* Verify signature of given message
*
* #param string $string
* #return boolean
*/
public static function verify($string){
$gpg = new Crypt_GPG();
$signatures = $gpg->verify($string);
if ($signatures[0]->isValid()) {
return true;
}
else{
return false;
}
}
/**
* Encrypt and sign given string to one or more recipients
*
* #param string $string
* #param string|array $encryptKeyID
* #param string $signkeyID
* #param string $signkeyPassword
* #param boolean $mode
* #param boolean $armor
* #return string
*/
public static function encryptAndSign($string, $encryptKeyID, $signkeyID, $signkeyPassword = null, $mode = null, $armor = true){
$gpg = new Crypt_GPG();
if($mode === null){
$mode = Crypt_GPG::SIGN_MODE_CLEAR;
}
$gpg->addSignKey($signkeyID, $signkeyPassword);
if(is_array($encryptKeyID)){
foreach($encryptKeyID as $keyId){
$gpg->addEncryptKey($keyId);
}
}
else{
$gpg->addEncryptKey($encryptKeyID);
}
return $gpg->encryptAndSign($string, $armor);
}
/**
* Decrypt and verify given string
*
* #param string $string
* #param string $keyID
* #param string $keyPassword
* #return array|false
*/
public static function decryptAndVerify($string, $keyID, $keyPassword = null){
$gpg = new Crypt_GPG();
$gpg->addDecryptKey($keyID, $keyPassword);
$result = $gpg->decryptAndVerify($string);
if(empty($result['data']) and empty($result['signatures'])){
return false;
}
if(isset($result['signatures'][0])){
$result['signature'] = $result['signatures'][0]->isValid();
unset($result['signatures']);
}
return $result;
}
}

Related

phpdoc how to document #return for both success and fail

i'm trying to keep my php rest server properly documents, so i was wondering how do we document that the return value can be one of 2 ?
/**
* send email to a user that contain reset data
* it also create reset token, so if there was an old reset token it will be changed
*
* #param email $email {#type email"
* #return SuccessMessage|FailMessage
*/
public function getSearch($email){
// search for $email, if success return
if($this->doOperation()===true){
return new SuccessMessage($email);
}
return new FailMessage($email);
}
nowing that both FailMessage and SuccessMessage are just empty classes to act as a consistent data structure
something more like this.
class FailMessage extends Messages{
function __construct(string $message, int $uid) {
if(is_callable("parent::__construct")){
parent::__construct(...func_get_args());
}
$this->uid = $uid;
$this->message = $data;
}
}
/**
* send email to a user that contain reset data
* it also create reset token, so if there was an old reset token it will be changed
*
* #param email $email {#type email"
* #return object SuccessMessage|FailMessage
*/
Your own comment is Ok but for more you can add object type. Also read the following document from the official website:
returnTags-PHPDoc

Infusionsoft Place order api showing No method matching arguments: java.lang.String, java.lang.Integer error

I am working in infusionsoft place order api but getting this error.
No method matching arguments: java.lang.String, java.lang.Integer, java.lang.String, java.lang.String, java.lang.Integer, java.lang.Integer
This is my code of api.
<?php
require_once("isdk.php");
$client = new xmlrpc_client("https://dv331.infusionsoft.com/api/xmlrpc");
###Return Raw PHP Types###
$client->return_type = "phpvals";
###Dont bother with certificate verification###
$client->setSSLVerifyPeer(FALSE);
class infusionsoft extends iSDK {
public $appName, $information;
public function __construct() {
include('conn.cfg.php');
foreach ($connInfo as $appLine) {
$nameIs['appName'] = substr($appLine, 0, strpos($appLine, ":"));
}
$this->appName = $nameIs['appName'];
if ($this->cfgCon($this->appName)) {
//echo "You Are Connected To Infusionsoft !";
} else {
echo "You Are Not Connected To Infusionsoft !";
exit();
}
}
}
$app = new infusionsoft();
$carray = array(
$key,
#contactId,
$CreditId,
$planId,
array(100,101),
array(100,101),
false,
array("MyPlan1","MyPlan2"));
$result = $app->placeOrder($carray);
I assume from your code that old Infusionsoft SDK is in use.
Than here's the source of the method placeOrder() you're calling:
/**
* #method placeOrder
* #description Builds, creates and charges an order.
* #param int $contactId
* #param int $creditCardId
* #param int $payPlanId
* #param array $productIds
* #param array $subscriptionIds
* #param bool $processSpecials
* #param array $promoCodes
* #param int $leadAff
* #param int $saleAff
* #return array
*/
public function placeOrder($contactId, $creditCardId, $payPlanId, $productIds, $subscriptionIds, $processSpecials, $promoCodes, $leadAff = 0, $saleAff = 0)
{
$carray = array(
php_xmlrpc_encode((int)$contactId),
php_xmlrpc_encode((int)$creditCardId),
php_xmlrpc_encode((int)$payPlanId),
php_xmlrpc_encode($productIds),
php_xmlrpc_encode($subscriptionIds),
php_xmlrpc_encode($processSpecials),
php_xmlrpc_encode($promoCodes),
php_xmlrpc_encode((int)$leadAff),
php_xmlrpc_encode((int)$saleAff));
return $this->methodCaller("OrderService.placeOrder", $carray);
}
Therefore, the first parameter to send is $contactId, API key is added implicitly.
Sent parameters are also type-casted internally, so you shouldn't have any issues as long as correct parameters are provided.

How to setup external Single Sign On for MediaWiki?

I'm trying to setup single sign on for MediaWiki with ExtAuthDB extension. The purpose is to authenticate user from external user system automatically when user logins in the main website: www.mysite.com. Mediawiki is located on subdomain: www.wiki.mysite.com.
I have installed the extension as it said in the guide. All priviliges are correct. But it doesn't work.
ExtAuthDB.php is:
<?php
/**
* Authentication plugin interface. Instantiate a subclass of AuthPlugin
* and set $wgAuth to it to authenticate against some external tool.
*
* The default behavior is not to do anything, and use the local user
* database for all authentication. A subclass can require that all
* accounts authenticate externally, or use it only as a fallback; also
* you can transparently create internal wiki accounts the first time
* someone logs in who can be authenticated externally.
*
* This interface is a derivation of AuthJoomla and might change a bit before 1.4.0 final is done...
*
*/
$wgExtensionCredits['parserhook'][] = array (
'name' => 'ExtAuthDB',
'author' => 'Alessandra Bilardi',
'description' => 'Authenticate users about external MySQL database',
'url' => 'https://www.mediawiki.org/wiki/Extension:ExtAuthDB',
'version' => '0.1',
);
require_once ( "$IP/includes/AuthPlugin.php" );
class ExtAuthDB extends AuthPlugin
{
/**
* Add into LocalSettings.php the following code:
*
* MySQL Host Name.
* $wgExtAuthDB_MySQL_Host = '';
* MySQL Username.
* $wgExtAuthDB_MySQL_Username = '';
* MySQL Password.
* $wgExtAuthDB_MySQL_Password = '';
* MySQL Database Name.
* $wgExtAuthDB_MySQL_Database = '';
* MySQL Database Table of users data.
* $wgExtAuthDB_MySQL_Table = '';
* MySQL Database username column label.
* $wgExtAuthDB_MySQL_Login = '';
* MySQL Database login password column label
* $wgExtAuthDB_MySQL_Pswrd = '';
* MySQL Database email column label
* $wgExtAuthDB_MySQL_Email = '';
* MySQL Database user real name column label
* $wgExtAuthDB_MySQL_RealN = '';
* require_once("$IP/extensions/ExtAuthDB/ExtAuthDB.php");
* $wgAuth = new ExtAuthDB();
*
* #return Object Database
*/
private function connectToDB()
{
$db = & Database :: newFromParams(
$GLOBALS['wgExtAuthDB_MySQL_Host'],
$GLOBALS['wgExtAuthDB_MySQL_Username'],
$GLOBALS['wgExtAuthDB_MySQL_Password'],
$GLOBALS['wgExtAuthDB_MySQL_Database']);
$this->userTable = $GLOBALS['wgExtAuthDB_MySQL_Table'];
$this->userLogin = $GLOBALS['wgExtAuthDB_MySQL_Login'];
$this->userPswrd = $GLOBALS['wgExtAuthDB_MySQL_Pswrd'];//.$GLOBALS['$wgExtAuthDB_MySQL_Salt'];
$this->userEmail = $GLOBALS['wgExtAuthDB_MySQL_Email'];
$this->userRealN = $GLOBALS['wgExtAuthDB_MySQL_RealN'];
wfDebug("ExtAuthDB::connectToDB() : DB failed to open\n");
return $db;
}
/**
* Check whether there exists a user account with the given name.
* The name will be normalized to MediaWiki's requirements, so
* you might need to munge it (for instance, for lowercase initial
* letters).
*
* #param $username String: username.
* #return bool
* #public
*/
function userExists( $username ) {
# Override this!
return true;
}
/**
* Check if a username+password pair is a valid login.
* The name will be normalized to MediaWiki's requirements, so
* you might need to munge it (for instance, for lowercase initial
* letters).
*
* #param $username String: username.
* #param $password String: user password.
* #return bool
* #public
*/
function authenticate( $username, $password )
{
$db = $this->connectToDB();
$hash_password = $db->selectRow($this->userTable,array ($this->userPswrd), array ($this->userLogin => $username ), __METHOD__ );
if ($password == $hash_password->{$this->userPswrd}) {
return true;
}
return false;
}
/**
* Set the domain this plugin is supposed to use when authenticating.
*
* #param $domain String: authentication domain.
* #public
*/
function setDomain( $domain ) {
$this->domain = $domain;
}
/**
* Check to see if the specific domain is a valid domain.
*
* #param $domain String: authentication domain.
* #return bool
* #public
*/
function validDomain( $domain ) {
# Override this!
return true;
}
/**
* When a user logs in, optionally fill in preferences and such.
* For instance, you might pull the email address or real name from the
* external user database.
*
* The User object is passed by reference so it can be modified; don't
* forget the & on your function declaration.
*
* #param User $user
* #public
*/
function updateUser( &$user )
{
$db = $this->connectToDB();
$euser = $db->selectRow($this->userTable,array ( '*' ), array ($this->userLogin => $user->mName ), __METHOD__ );
$user->setRealName($euser->{$this->userRealN});
$user->setEmail($euser->{$this->userEmail});
$user->mEmailAuthenticated = wfTimestampNow();
$user->saveSettings();
//exit;
# Override this and do something
return true;
}
function disallowPrefsEditByUser() {
return array (
'wpRealName' => true,
'wpUserEmail' => true,
'wpNick' => true
);
}
/**
* Return true if the wiki should create a new local account automatically
* when asked to login a user who doesn't exist locally but does in the
* external auth database.
*
* If you don't automatically create accounts, you must still create
* accounts in some way. It's not possible to authenticate without
* a local account.
*
* This is just a question, and shouldn't perform any actions.
*
* #return bool
* #public
*/
function autoCreate() {
return true;
}
/**
* Can users change their passwords?
*
* #return bool
*/
function allowPasswordChange() {
return false;
}
/**
* Set the given password in the authentication database.
* As a special case, the password may be set to null to request
* locking the password to an unusable value, with the expectation
* that it will be set later through a mail reset or other method.
*
* Return true if successful.
*
* #param $user User object.
* #param $password String: password.
* #return bool
* #public
*/
function setPassword( $user, $password ) {
return true;
}
/**
* Update user information in the external authentication database.
* Return true if successful.
*
* #param $user User object.
* #return bool
* #public
*/
function updateExternalDB( $user ) {
$db = $this->connectToDB();
$euser = $db->selectRow($this->userTable,array ( '*' ), array ($this->userLogin => $user->mName ), __METHOD__ );
$user->setRealName($euser->{$this->userRealN});
$user->setEmail($euser->{$this->userEmail});
$user->mEmailAuthenticated = wfTimestampNow();
$user->saveSettings();
return true;
}
/**
* Check to see if external accounts can be created.
* Return true if external accounts can be created.
* #return bool
* #public
*/
function canCreateAccounts() {
return false;
}
/**
* Add a user to the external authentication database.
* Return true if successful.
*
* #param User $user - only the name should be assumed valid at this point
* #param string $password
* #param string $email
* #param string $realname
* #return bool
* #public
*/
function addUser( $user, $password, $email='', $realname='' ) {
return false;
}
/**
* Return true to prevent logins that don't authenticate here from being
* checked against the local database's password fields.
*
* This is just a question, and shouldn't perform any actions.
*
* #return bool
* #public
*/
function strict() {
return true;
}
/**
* When creating a user account, optionally fill in preferences and such.
* For instance, you might pull the email address or real name from the
* external user database.
*
* The User object is passed by reference so it can be modified; don't
* forget the & on your function declaration.
*
* #param $user User object.
* #param $autocreate bool True if user is being autocreated on login
* #public
*/
function initUser( $user, $autocreate=false ) {
# Override this to do something.
}
/**
* If you want to munge the case of an account name before the final
* check, now is your chance.
*/
function getCanonicalName( $username ) {
return $username;
}
}
And in LocalSettings.php, I should add this code:
// add ExtAuthDB
// MySQL Host Name.
$wgExtAuthDB_MySQL_Host = 'localhost';
// MySQL Username.
$wgExtAuthDB_MySQL_Username = 'dbuser';
// MySQL Password.
$wgExtAuthDB_MySQL_Password = 'dbpassword';
// MySQL Database Name.
$wgExtAuthDB_MySQL_Database = 'base';
// MySQL Database Table of users data.
$wgExtAuthDB_MySQL_Table = 'members';
// MySQL Database username column label.
$wgExtAuthDB_MySQL_Login = 'username';
// MySQL Database login password column label
$wgExtAuthDB_MySQL_Pswrd = 'password';
$wgExtAuthDB_MySQL_Salt='salt';
// MySQL Database email column label
$wgExtAuthDB_MySQL_Email = 'email';
// MySQL Database user real name column label
$wgExtAuthDB_MySQL_RealN = 'real_name';
require_once("$IP/extensions/ExtAuthDB/ExtAuthDB.php");
$wgAuth = new ExtAuthDB();
Sorry, I had to copy full script, because I don't know where is the exact fault. And my question is: Why doesn't it work? Where is the mistake?
EDIT:
My external user table consists of id, username, password, salt, email, real_name. I thought it could be because of seperate password and salt fields, so I tried to implement salt in ExtAuthDB.php file manually. Unfortunately, it didn't work either. Then I commented this line.
I was able to setup SSO (Single sign-on) from WordPress to media wiki using OAuth 2.0 server, I have posted my solution on this post
Or you can follow these steps:
First you need an OAuth 2.0 server, you could implement it your self see details here Run your own OAuth 2.0 Server or the easiest way is to use the WordPress plugin WP Oauth 2.0 server you don't have to buy the pro, you can also implement SSO by using the Grant type Authorization codes which comes free.
You need OAuth 2.0 client extension installed on your media wiki, the extension can be found here, follow the installation instructions there.
Go to WordPress plugin page and activate OAuth server, then navigate to OAuth Server and add a new client, give your client a name and in Redirect URI add the link mention on the media wiki extension page i.e http://your.wiki.domain/path/to/wiki/Special:OAuth2Client/callback, then go to OAuth>clients page where you can see your newly created client, click edit and here you can see clientID and Client secret add this ID and secret in the localSettings.php of your media wiki.
Create a page on WordPress and put the following button with your client id in it
< a href="https://your-Domain-Where-OAuth-server-is-running.de/oauth/authorize?response_type=code&client_id=YOURCLIENTID&state=RANDOM-STRING&scope=basic">
go to wiki</a>
don't forget to put scope otherwise you will get a media wiki internal error.
If everything worked fine then you should automatically go to the media wiki main page after clicking this button from your WordPress. media wiki will show you as logged in. It took me some time to figure it out I hope this helps anyone who comes here.
You need to run the MediaWiki update script for this extension.
Many extensions need an update with update.php script!
From the browser
If you do not have access to the command line of your server, then use the web updater to run the update script.
From the command line
From the command line, or an SSH shell or similar:
Change to the maintenance directory!
Run the update script with php update.php command!

Restler 3 nested resources?

In restler, is is possible to use nested resources? For example, with restler I would do the normal /api/account/123 call to get that specific account. Now I want to get the clients that belong to that account. So I'd want to also call /api/account/123/client/456 for example to get the specific client for the specific account.
You can use manual routing to define such routes. See the following example
use Luracast\Restler\RestException;
class Accounts
{
/**
* Get specific client for the given account
*
* #param int $id account id
* #param int $client_id
*
* #throws RestException 404
*
* #return Client
*
* #url GET accounts/{id}/clients/{client_id}
*/
public function getClient($id, $client_id)
{
$r = Client::where('account_id', '=', $id)->where('id', '=', $client_id)->firstOrFail();
if (empty($r))
throw RestException(404, 'Client is not found associated with the account');
return $r;
}
/**
* Get all clients associated with the given account
*
* #param int $id account id
*
* #return array {#type Client}
*
* #url GET accounts/{id}/clients
*/
public function getClients($id)
{
return Client::where('account_id', '=', $id)->all();
}
}

How to use SHA1 encryption instead of BCrypt in Laravel 4?

I'm developing a so called AAC (Automatic Account Creator) for a game, it's basically a site with functions to create accounts, players and several more things for players. The server only supports SHA1 and plain - which is totally unsafe. I can't dive into the source code and make changes. If there's anyway to use SHA1 I would be grateful. I just read about BCrypt, it's great but I can't really change the source code to suit BCrypt. I managed to put SHA1 on registration like this:
$password = $input['password'];
$password = sha1($password);
But I simply can't login. am I doing it wrong? seems like Laravel won't let me login.
I've got get_register and post_register, also I've got get_login and post_login. Do i need to change something in the post_login to make it login or?
any hints?
I'm using Laravel's php server (php artisan serve) and phpMyAdmin on WAMP. I think Laravel checks when you are checking the DB via the Auth::attempt method laravel is doing some form of hashing to check the current pw and the logged in one to check against each other.
You'll have to rewrite the Hash module. Thanks to Laravel's ideas of following IoC and Dependency Injection concepts, it'll be relatively easy.
First, create a app/libraries folder and add it to composer's autoload.classmap:
"autoload": {
"classmap": [
// ...
"app/libraries"
]
},
Now, it's time we create our class. Create a SHAHasher class, implementing Illuminate\Hashing\HasherInterface. We'll need to implement its 3 methods: make, check and needsRehash.
Note: On Laravel 5, implement Illuminate/Contracts/Hashing/Hasher instead of Illuminate\Hashing\HasherInterface.
app/libraries/SHAHasher.php
class SHAHasher implements Illuminate\Hashing\HasherInterface {
/**
* Hash the given value.
*
* #param string $value
* #return array $options
* #return string
*/
public function make($value, array $options = array()) {
return hash('sha1', $value);
}
/**
* Check the given plain value against a hash.
*
* #param string $value
* #param string $hashedValue
* #param array $options
* #return bool
*/
public function check($value, $hashedValue, array $options = array()) {
return $this->make($value) === $hashedValue;
}
/**
* Check if the given hash has been hashed using the given options.
*
* #param string $hashedValue
* #param array $options
* #return bool
*/
public function needsRehash($hashedValue, array $options = array()) {
return false;
}
}
Now that we have our class done, we want it to be used by default, by Laravel. To do so, we'll create SHAHashServiceProvider, extending Illuminate\Support\ServiceProvider, and register it as the hash component:
app/libraries/SHAHashServiceProvider.php
class SHAHashServiceProvider extends Illuminate\Support\ServiceProvider {
/**
* Register the service provider.
*
* #return void
*/
public function register() {
$this->app['hash'] = $this->app->share(function () {
return new SHAHasher();
});
}
/**
* Get the services provided by the provider.
*
* #return array
*/
public function provides() {
return array('hash');
}
}
Cool, now all we have to do is make sure our app loads the correct service provider. On app/config/app.php, under providers, remove the following line:
'Illuminate\Hashing\HashServiceProvider',
Then, add this one:
'SHAHashServiceProvider',
It took me a lot of time to get something similar happening in Laravel 5.6 but this thread was invaluable. The accepted answer gets you very close but there are still some ambushes along the way (as can be seen in the comments) so instead of struggling with the comments I thought it would be helpful for others to have it presented as an answer.
In my case I needed to access an existing database and couldn't change the user file. The passwords were saved in SHA256 format with a hash key applied as well. So the objective for me was to really only get the check function working.
I'm really new to Laravel and I know there will be a better way around this issue but I couldn't get the app\Libraries area to register so I put both SHAHasher.php and SHAHashServiceProvider.php into app\Providers which I would assume is some sort of Laravel sacrilege but it was the only way I got it to work. :)
The steps I took (hijacking rmobis's excellent answer for Laravel 4) was:
The hash key used in the original app needed to be accessed by Laravel so I added this to the bottom of .env.
.env
...
HASH_KEY=0123_key_code_added_here_xyz
app/Providers/SHAHasher.php
namespace App\Providers;
use Illuminate\Contracts\Hashing\Hasher;
class SHAHasher implements Hasher
{
/**
* Get information about the given hashed value.
* TODO: This was added to stop the abstract method error.
*
* #param string $hashedValue
* #return array
*/
public function info($hashedValue)
{
return password_get_info($hashedValue);
}
/**
* Hash the given value.
*
* #param string $value
* #return array $options
* #return string
*/
public function make($value, array $options = array())
{
// return hash('sha1', $value);
// Add salt and run as SHA256
return hash_hmac('sha256', $value, env('HASH_KEY'));
}
/**
* Check the given plain value against a hash.
*
* #param string $value
* #param string $hashedValue
* #param array $options
* #return bool
*/
public function check($value, $hashedValue, array $options = array())
{
return $this->make($value) === $hashedValue;
}
/**
* Check if the given hash has been hashed using the given options.
*
* #param string $hashedValue
* #param array $options
* #return bool
*/
public function needsRehash($hashedValue, array $options = array())
{
return false;
}
}
app/Providers/SHAHashServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class SHAHashServiceProvider extends ServiceProvider {
/**
* Register the service provider.
*
* #return void
*/
public function register() {
$this->app->singleton('hash', function() {
return new SHAHasher();
});
}
/**
* Get the services provided by the provider.
*
* #return array
*/
public function provides() {
return array('hash');
}
}
app/config/app.php
remove or comment out // Illuminate\Hashing\HashServiceProvider::class,
Add App\Providers\SHAHashServiceProvider::class,
I didn't need to register the users (only to allow them to use their existing logins to get in) so I only tested it for access. I'm not sure why the app/Libraries area wouldn't take. I was getting an error
Class 'SHAHashServiceProvider' not found
when I ran the composer dump-autoload command until I moved both into app/Providers.
Hope this helps others trying to get the anser to work in Laravel 5.
There is actually a easier (or more simple, at least) solution for a case like this. you can 'fake' the hashing, by using this method in the user model:
public function getAuthPassword() {
return Hash::make($this->password);
}
And hashing the input with your own hash function. For instance, if your passwords are currently hashed with sha1, you can validate the user with
Auth::attempt(array('email' => $email, 'password' => sha1($password))
It doesn't feel like good coding practice, to do it this way, but it will certainly be easier than rewriting the hash module.
The Laravel 7 way
In Laravel 7 adding new hash methods to Laravel got a lot easier you can also still support the old Hash methods instead of basically overwriting them.
First we will create a subfolder in the app folder called Libs or Libaries or basically whatever you want to call it.
In that folder I created a folder called CustomHash where I store all my custom hashers.
Through PSR-4 it is automatically detected and we do not need to add it anywhere.
The Namespace is based on the folder names I chose.
app/AppServiceProvider.php
First we use the namespace of the Sha1Hasher
use App\Libs\CustomHash\Sha1Hasher;
then in the boot() function of your AppServiceProvide.php
Hash::extend("sha1", function($app)
{
return new Sha1Hasher();
});
app/Libs/CustomHash/Sha1Hasher.php
<?php
namespace App\Libs\CustomHash;
use Illuminate\Contracts\Hashing\Hasher as HasherContract;
use Illuminate\Hashing\AbstractHasher;
class Sha1Hasher extends AbstractHasher implements HasherContract {
/**
* Hash the given value.
*
* #param string $value
* #return array $options
* #return string
*/
public function make($value, array $options = array()) {
//I have custom encoding / encryption here//
//Define your custom hashing logic here//
return sha1($value);
}
/**
* Check the given plain value against a hash.
*
* #param string $value
* #param string $hashedValue
* #param array $options
* #return bool
*/
public function check($value, $hashedValue, array $options = array()) {
return $this->make($value) === $hashedValue;
}
/**
* Check if the given hash has been hashed using the given options.
*
* #param string $hashedValue
* #param array $options
* #return bool
*/
public function needsRehash($hashedValue, array $options = array()) {
return false;
}
}
And that's basically it if you want to change the default hash algorithm for everything there is one more thing to do:
config/hashing.php
Change the default driver for hashing to the sha1 driver we implemented with the edits above.
'driver' => 'sha1',
You can do this
dd(
sha1(55),
hash('sha1', 55),
hash_hmac('sha1', 55, env('APP_KEY')),
hash_hmac('sha256', 55, env('APP_KEY')),
hash_hmac('sha512', 55, env('APP_KEY')),
);
// outputs:
/*
"8effee409c625e1a2d8f5033631840e6ce1dcb64"
"8effee409c625e1a2d8f5033631840e6ce1dcb64"
"a2ebb15e6747d1c09f2754787ab390d35c24996e"
"f0fadaa9fdd518947ac3f698196d5370dc2409bbdfbe9e37bd30f935b6cc1f47"
"c1e6f4e144565aa4fdb9c7ae34aba7d43424e20fa40ad3a0641d20bfbb3b9681ded4f4cc8b4661804e4a753118a3f984585d6915ee6d4b75a95310af48afe920"
*/
Laravel 7 UPD
same as Das123 answer but a little fix to
app/Providers/SHAHashServiceProvider.php
namespace App\Libraries\ShaHash;
use Illuminate\Contracts\Hashing\Hasher as HasherContract;
use Illuminate\Hashing\AbstractHasher;
class SHAHasher extends AbstractHasher implements HasherContract
/**
* Register the service provider.
*
* #return void
*/
public function register() {
$this->app->singleton('hash', function() {
return new SHAHasher();
});
}
/**
* Get the services provided by the provider.
*
* #return array
*/
public function provides() {
return array('hash');
}
}

Categories