Is there is any way to retrieve users email address. I am using hybrid auth. Login works no email address obtained only got access userid , display name & display picture.
Is there any method to get access to email address of user,
Everything is working fine except . The response gives a blank email
class Yahoo extends OAuth2
{
protected $scope = 'sdct-r';
protected $apiBaseUrl = 'https://social.yahooapis.com/v1/';
protected $authorizeUrl = 'https://api.login.yahoo.com/oauth2/request_auth';
protected $accessTokenUrl = 'https://api.login.yahoo.com/oauth2/get_token';
protected $apiDocumentation = 'https://developer.yahoo.com/oauth2/guide/';
protected $userId = null;
protected function initialize()
{
parent::initialize();
$this->tokenExchangeHeaders = [
'Authorization' => 'Basic ' . base64_encode($this->clientId . ':' . $this->clientSecret) ]; }
protected function getCurrentUserId()
{
if ($this->userId) {
return $this->userId;
}
$response = $this->apiRequest('me/guid', 'GET', [ 'format' => 'json']);
$data = new Data\Collection($response);
if (! $data->filter('guid')->exists('value')) {
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
}
return $this->userId = $data->filter('guid')->get('value');
}
public function getUserProfile()
{
// Retrieve current user guid if needed
$this->getCurrentUserId();
$response = $this->apiRequest('user/' . $this->userId . '/profile', 'GET', [ 'format' => 'json']);
$data = new Data\Collection($response);
if (! $data->exists('profile')) {
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
}
$userProfile = new User\Profile();
$data = $data->filter('profile');
$userProfile->identifier = $data->get('guid');
$userProfile->firstName = $data->get('givenName');
$userProfile->lastName = $data->get('familyName');
$userProfile->displayName = $data->get('nickname');
$userProfile->photoURL = $data->filter('image')->get('imageUrl');
$userProfile->profileURL = $data->get('profileUrl');
$userProfile->language = $data->get('lang');
$userProfile->address = $data->get('location');
if ('F' == $data->get('gender')) {
$userProfile->gender = 'female';
} elseif ('M' == $data->get('gender')) {
$userProfile->gender = 'male';
}
// I ain't getting no emails on my tests. go figures..
foreach ($data->filter('emails')->toArray() as $item) {
if ($item->primary) {
$userProfile->email = $item->handle;
$userProfile->emailVerified = $item->handle;
}
}
return $userProfile;
}
}
from the Yahoo guide:
The extended profile scope sdpp-w, in addition to the Claims given
above, also returns the following Claims:
email - the email ID of the user
email_verified - the Boolean flag letting Clients know if the given email address has been verified by Yahoo.
Please upgrade Hybridauth to 3.0-rc.10 which is fixed that issue for Yahoo provider.
See original PR with fix: https://github.com/hybridauth/hybridauth/pull/986
Related
I'm trying to register a credit card with MangoPay.
I've installed the mangopay/php-sdk-v2 package.
To register a credit card, it needs three steps.
Create a token of the card
Post card info (using a url created by the token) that will render a string that start with data=
Add the registered card to the MangoPay user
// ProfilController.php
/**
* #Route("/payment/{id}", name="payment")
* * #param int $id
*/
public function payment(Request $request, ApiUser $ApiUser, $id): Response
{
$returnUrl = "";
$user = $this->userRepository->findOneBy(['id' => $id]);
$userId = $user->getIdMangopay();
$registration = $ApiUser->Registration($userId);
if($request->request->count() > 0){
$payment = new PaymentMethod();
$payment->setName($request->request->get('name'));
$payment->setCardNumber($request->request->get('cardNumber'));
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($payment);
$entityManager->flush();
$registrationCard = $ApiUser->RegistrationCard($registration, $request);
$returnUrl = 'http' . (isset($_SERVER['HTTPS']) ? 's' : '') . '://' . $_SERVER['HTTP_HOST'];
$returnUrl .= '/profil';
}
return $this->render('home/payment.html.twig', [
'CardRegistrationUrl' => $registration->CardRegistrationURL,
'Data' => $registration->PreregistrationData,
'AccessKeyRef' => $registration->AccessKey,
'returnUrl' => $returnUrl,
]);
}
The Registration and ResitrationCard functions come from the ApiUser file:
// ApiUser.php
public function Registration($UserId)
{
$CardRegistration = new \MangoPay\CardRegistration();
$CardRegistration->UserId = $UserId;
$CardRegistration->Currency = "EUR";
$CardRegistration->CardType = "CB_VISA_MASTERCARD";
$Result = $this->mangoPayApi->CardRegistrations->Create($CardRegistration);
$this->registrationInfo = $Result;
$this->CardRegistrationUrl = $Result->CardRegistrationURL;
return $Result;
}
public function RegistrationCard($CardInfo)
{
$cardRegister = $this->mangoPayApi->CardRegistrations->Get($CardInfo->Id);
$cardRegister->RegistrationData = $_SERVER['QUERY'];
$updatedCardRegister = $this->mangoPayApi->CardRegistrations->Update($cardRegister);
return $Result;
}
I'm able to create the token of the card and get the data= string, but the problem is that I cannot do the last step.
It seems that I cannot enter into the if statement, so it doesn't register the card on the database and I cannot update the card information (3rd step).
The returnUrl, I can simply put it outside of the if statement to make it works, but I want to change it only if the form is valid.
How can I fix the statement? Why doesn't it enter into the if?
Please try to use the regular form validation process of Symfony, and let me know if this helps.
To do this, you need to customize the input name attribute for it to match the payment API config.
In your Type class:
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
// ...
->add('new-input-name-goes-here', TextType::class, [
'property_path' => '[data]'
]);
}
public function getBlockPrefix()
{
return '';
}
I'm trying to change some property values of my account object. I'm trying to set a value on domain and password
When I log my object before I send it over to my front end (using vue), the object seems to be modified to my needs, but when I console.log() it in the browser the property values are null.
I'm using Laravel excel to create the accounts. After an account is created I use events with listeners to send my account objects to my view with pusher.
How do I do this properly?
AccountsImport
class AccountsImport implements ToCollection, withHeadingRow
{
use Importable;
private $data;
public function __construct(array $data = [])
{
$this->data = $data;
}
public function collection(Collection $rows)
{
$rows->each(function ($row, $key) {
$account = Account::create(array_merge([
'name' => mb_convert_encoding($row['student'], "UTF-8", mb_detect_encoding($row['student'], "UTF-8, ISO-8859-1, ISO-8859-15", true)),
'email' => $row['school_e_mailadres'],
], $this->data));
event(new AccountCreation($account));
});
}
}
AccountCreation event gets fired and SetHostingAccount listener will run
public function handle(AccountCreation $event)
{
$generator = new ComputerPasswordGenerator();
$generator->setUppercase()->setLowercase()->setNumbers()->setSymbols(false)->setLength(20);
$password = $generator->generatePassword();
$domain = preg_replace('/\s+/', '.', mb_strtolower($event->account->name . ' mtantwerp.eu'));
$event->account->{"domain"} = $domain;
$event->account->{"password"} = $password;
\Log::debug($event->account);
return $event->account;
}
Vue
created() {
Echo.channel("account-channel").listen("AccountCreation", e => {
console.log(e.account);
this.accounts.unshift(e.account);
});
}
Log results
Example result of \Log::debug($event->account)
{"name":"John Doe","email":"john.doe#student.kdg.be","package":"KDG student","id":577,"domain":"john.doe.mtantwerp.eu","password":"r5RSEvQBYnTF7RkPtL8Y"}
Console.log(e.account) in view
Object
domain: null
email: "john.doe#student.kdg.be"
id: 703
name: "Doe John"
package: "KDG student"
password: null
status: "created"
It seems you are not persisting your data to the model.
public function handle(AccountCreation $event)
{
$generator = new ComputerPasswordGenerator();
$generator->setUppercase()->setLowercase()->setNumbers()->setSymbols(false)->setLength(20);
$password = $generator->generatePassword();
$domain = preg_replace('/\s+/', '.', mb_strtolower($event->account->name . ' mtantwerp.eu'));
$event->account->{"domain"} = $domain;
$event->account->{"password"} = $password;
// persist
$event->account->save();
return $event->account;
}
Edit: I think there are two ways you can handle this.
Either you re-broadcast the event after updating your account details:
public function handle(AccountCreation $event)
{
$generator = new ComputerPasswordGenerator();
$generator->setUppercase()->setLowercase()->setNumbers()->setSymbols(false)->setLength(20);
$password = $generator->generatePassword();
$domain = preg_replace('/\s+/', '.', mb_strtolower($event->account->name . ' mtantwerp.eu'));
$event->account->{"domain"} = $domain;
$event->account->{"password"} = $password;
// persist
$event->account->save();
// broadcast will have updated account details
// after it was persisted
broadcast($event);
return $event->account;
}
In this case, you would also need to check for whether the account has a domain on the Vue component.
if(e.account.domain) {
this.accounts.unshift(e.account);
}
This should work. However, I'd rather you consider creating a new event which will better describe what you are tring to do.
In this case, the account is being updated. So you would create a new AccountWasUpdated event and you will have Echo listen to it instead.
public function handle(AccountCreation $event)
{
$generator = new ComputerPasswordGenerator();
$generator->setUppercase()->setLowercase()->setNumbers()->setSymbols(false)->setLength(20);
$password = $generator->generatePassword();
$domain = preg_replace('/\s+/', '.', mb_strtolower($event->account->name . ' mtantwerp.eu'));
$event->account->{"domain"} = $domain;
$event->account->{"password"} = $password;
// persist
$event->account->save();
event(new AccountWasUpdated($event->account));
return $event->account;
}
Instead of having Echo listen to the AccountCreation event, it would listen to the AccountWasUpdated event and it will contain the new Account Object.
I'm using yii2-dektrium to allow users login with their facebook's accounts.
After the login is done, I need to make API request from my server to get data of the user's accounts. One example of request is:
$client = Yii::$app->authClientCollection->getClient('facebook');
$response = $client->createApiRequest()
->setMethod('GET')
->setUrl('v2.12/me/accounts')
->send();
The access_token is saved on session so I need to persist it to the database.
I already added a column access_token to the social_account default table of yii2-dektrium but I don't know how to get and save it, and further more, how to apply it to the requests.
After reading for a while. I think the way to save it is overriding the method connect in dektrium\user\controllers\SecurityController.
public function connect(ClientInterface $client)
{
/** #var Account $account */
$account = \Yii::createObject(Account::className());
$event = $this->getAuthEvent($account, $client);
$this->trigger(self::EVENT_BEFORE_CONNECT, $event);
$account->connectWithUser($client);
$this->trigger(self::EVENT_AFTER_CONNECT, $event);
$this->action->successUrl = Url::to(['/user/settings/networks']);
}
And for applying to the request, override applyAccessTokenToRequest on yii\authclient\clients\Facebook
public function applyAccessTokenToRequest($request, $accessToken)
{
parent::applyAccessTokenToRequest($request, $accessToken);
$data = $request->getData();
if (($machineId = $accessToken->getParam('machine_id')) !== null) {
$data['machine_id'] = $machineId;
}
$data['appsecret_proof'] = hash_hmac('sha256', $accessToken->getToken(), $this->clientSecret);
$request->setData($data);
}
I can't get it done. And I'm not sure if it is the right way to do it. What I'm missing?
For save the access_token the first time you have to overwrite the connect action from \dektrium\user\controllers\SecurityController.
class SecurityController extends \dektrium\user\controllers\SecurityController
{
public function connect(ClientInterface $client)
{
// default implementation of connect
$account = \Yii::createObject(Account::className());
$event = $this->getAuthEvent($account, $client);
$this->trigger(self::EVENT_BEFORE_CONNECT, $event);
$account->connectWithUser($client);
$this->trigger(self::EVENT_AFTER_CONNECT, $event);
// get acess_token from $client
$access_token['tokenParamKey'] = $client->getAccessToken()->tokenParamKey;
$access_token['tokenSecretParamKey'] = $client->getAccessToken()->tokenSecretParamKey;
$access_token['createTimestamp'] = $client->getAccessToken()->createTimestamp;
$access_token['_expireDurationParamKey'] = $client->getAccessToken()->getExpireDurationParamKey();
$access_token['_params'] = $client->getAccessToken()->getParams();
// save acess_token to social_account table
$model = SocialAccount::find()->where(['provider' => $client->getName()])->andWhere(['user_id' => Yii::$app->user->id])->one();
$model->access_token = \yii\helpers\Json::encode($access_token);
$model->save(false);
$this->action->successUrl = Url::to(['/user/settings/networks']);
}
}
To get the access_token store in the database for further API Requests create a class that extends yii\authclient\SessionStateStorage and overwrite get method.
namespace app\models\authclient;
class DbStateStorage extends SessionStateStorage
{
public function get($key)
{
// $key is a complex string that ends with 'token' if the value to get is the actual access_token
$part = explode('_', $key);
if (count($part) == 3 && $part[2] == 'token') {
$account = SocialAccount::find()
->where(['provider' => $part[1]])
->andWhere(['user_id' => Yii::$app->user->id])
->one();
if ($account != null) {
$access_token = json_decode($account->access_token);
$token = new \yii\authclient\OAuthToken();
$token->createTimestamp = $access_token->createTimestamp;
$token->tokenParamKey = $access_token->tokenParamKey;
$token->tokenSecretParamKey = $access_token->tokenSecretParamKey;
$token->setParams((array)$access_token->_params);
$token->setExpireDurationParamKey($access_token->_expireDurationParamKey);
return $token;
}
}
if ($this->session !== null) {
return $this->session->get($key);
}
return null;
}
}
Finally set the DbStateStorage to your authclient
class Facebook extends \dektrium\user\clients\Facebook
{
public function __construct()
{
$this->setStateStorage('app\models\authclient\DbStateStorage');
}
}
I have a problem with the Google API. I need to get all the contacts of a user in my application, however I don't want to load all the data each time, because I store the data in my database.
It's why I want to use the Sync Token functionality which let's us get only data who has been changed since our last query.
For this i Use the Google APIs PHP client library.
I wrote my code and it throws an exception (Google_Service_Exception) which explains that my Sync Token is not valid anymore, so I decided to use a try/catch system to reset syncToken if it is not valid.
My problem is each time i made the request I go in the catch (the google_service_exception) is raised even if my token is valid.
I store the token in my database so I tested it in the API explorer here: https://developers.google.com/people/api/rest/v1/people.connections/list and it work fine, so I don't understand why my application doesn't work properly.
Here's my code:
$personFields = 'metadata,names,addresses,biographies,birthdays,emailAddresses,genders,memberships,organizations,phoneNumbers';
$user = $this->get('security.token_storage')->getToken()->getUser();
$syncToken = $user->getContactSyncToken();
$nextPagetoken = '';
$contactData = array();
$people_service = new \Google_Service_PeopleService($client);
do {
try {
$data = $people_service->people_connections->listPeopleConnections(
'people/me',
array(
'personFields' => $personFields,
'requestSyncToken' => true,
'syncToken' => $syncToken,
'pageToken' => $nextPagetoken,
)
);
}catch (\Google_Service_Exception $e){
$data = $people_service->people_connections->listPeopleConnections(
'people/me',
array(
'personFields' => $personFields,
'requestSyncToken' => true,
'syncToken' => '',
'pageToken' => $nextPagetoken,
)
);
}finally{
$syncToken = $data->getNextSyncToken();
$nextPagetoken = $data->getNextPageToken();
if (count($data->getConnections()) != 0) {
$contactData[] = $data->getConnections();
}
}
}while ($nextPagetoken !== null);
$user->setContactSyncToken($syncToken);
$this->getDoctrine()->getManager()->flush();
return $contactData;
Thank you for your help and sorry for my english i'm not a native and not very good at it.
Sorry i found the problem, in my User class i had:
public function getContactSyncToken()
{
if($token = $this->contactSyncToken !== null){
return $token;
}else{
return '';
}
}
And it always return ' ', now it works with:
public function getContactSyncToken()
{
$token = $this->contactSyncToken;
if($token !== null){
return $token;
}else{
return '';
}
}
I am trying to resolve a bug on a client's application, but i can't log in.
So i go to application.dev/metier/login, with application.dev as my virtual host, metier my admin route page and login the page to log in the application.
I complete the form, click on connect, i am getting logged in, redirected to the index page (application.dev/metier/index) but immediately after the redirection i am kicked out to the login page. The url is still application.dev/metier/index, but the i am seeing the login page as i was not authenticated.
I checked session, cleared after redirection.
It is like it's working fine, I am known from database, inserted in session, known as admin, but kicked out no matter what i do. No error, no log. Zend do not enter indexAction().
I can't go to another page due to the routing, and if i try to put my informations in session before access login page, i have an error "too many redirections" (i am in authenticated so go to index, but no i am kicked out, but i am authenticated, but i am kicked out...).
I am on Zend framework 1.12.18, Windows 10, with laragon (Kaspersky as antivirus). I also tried with wamp, and on an Ubuntu VM with xampp, same problem. I tried on another computer, same problem.
It works on the developer who gave me the source code. He gave me the original code and the code with his modification (of application.ini mainly), both give me the "error".
Controller:
public function loginAction() {
try {
$auth = Zend_Auth::getInstance();
if ($auth->hasIdentity()) {
$this->redirect('/metier/index/');
return;
}else{
Zend_Session::regenerateId();
}
$loginForm = new Application_Form_Admin_Login();
$request = $this->getRequest();
if ($request->isPost()) {
if ($loginForm->isValid($request->getPost())) {
if ($this->_process($loginForm->getValues())) {
// We're authenticated! Redirect to the home page
$this->_helper->redirector('index', 'index');
}
} else {
Log::debug('User sent invalid data.', __FILE__, __LINE__);
Log::debug($request->getPost(), __FILE__, __LINE__);
Log::debug('Errors: ', __FILE__, __LINE__);
Log::debug($loginForm->getErrors(), __FILE__, __LINE__);
$this->view->error = Zend_Registry::get('Language')->errors->login->error;
}
}
} catch (Exception $e) {
//$this->view->error = 'Wrong username and/or password';
$this->redirect('/metier/login/');
return;
}
$this->view->form = $loginForm;
}
protected function _process($values) {
if (!trim($values['username']) || !trim($values['password'])) {
$this->view->error = Zend_Registry::get('Language')->errors->login->empty;
return false;
}
// Get our authentication adapter and check credentials
$adapter = $this->_getAuthAdapter();
$adapter->setIdentity($values['username']);
$adapter->setCredential($values['password']);
$auth = Zend_Auth::getInstance();
$result = $auth->authenticate($adapter);
Log::debug('Authentication returned result code: ' . $result->getCode(), __FILE__, __LINE__);
switch ($result->getCode()) {
case Zend_Auth_Result::SUCCESS:
$mdlMetierDep = new Application_Model_DbTable_MetierDepartement();
$user = $adapter->getResultRowObject();
$metDepObj = $mdlMetierDep->fetchRow(array('id_metier = ?' => $user->id_metier, 'id_departement = ?' => $user->id_departement));
if (!$metDepObj) {
$this->view->error = Zend_Registry::get('Language')->errors->login->error;
return $this->_redirect('/metier/login/');
}
$user->Role = Acl::ROLE_ADMIN_METIER;
$user->id_metier_departement = $metDepObj->getIdMetierDepartement();
$user->metier = $metDepObj->findMetier()->toArray();
$user->department = $metDepObj->findDepartement()->toArray();
// to help thwart session fixation/hijacking
// store user object in the session
$authStorage = $auth->getStorage();
$authStorage->write($user);
$this->_redirect('/metier/index/');
break;
case Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND:
case Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID:
default:
$this->view->error = Zend_Registry::get('Language')->errors->login->error;
break;
}
if ($result->isValid()) {
$user = $adapter->getResultRowObject();
//$auth->getStorage()->write($user);
return true;
}
return false;
}
The login and reporting actions (just for informations, zend do not goes in it)
public function indexAction() {
$this->go('reporting');
}
public function reportingAction() {
$this->loadJs(('/scripts/metier/general.js'));
$this->loadCss(('/styles/metier/DataTable.css'));
$this->loadJs(('/scripts/jquery.dataTables.js'));
$this->loadJs(('/scripts/metier/data-table.js'));
}
Init function :
public function init() {
/* Initialize action controller here */
parent::init();
$this->loadCss(('/styles/web/tables2.css'));
$this->loadJs(('/scripts/web/tinyMceConfigs.js'));
$this->language = Zend_Registry::get('Language');
$this->view->language = $this->language;
$auth = Zend_Auth::getInstance();
if ($auth->hasIdentity()) {
$this->storage = $auth->getStorage()->read();
$this->_getLogo();
} else {
$this->view->noLogo = true;
}
//enum field for indicateurs
$this->view->frequence = array('M', 'T', 'S', 'A');
$this->view->sens = array(
'A' => 'Croissant',
'D' => 'Décroissant',
);
$this->view->formulaType = array(
0 => 'rule',
1 => 'min',
2 => 'max',
3 => 'avg');
$this->view->FormulaOperand = array(
0 => '+',
1 => '-',
2 => '/',
3 => '*');
$this->view->tableauTypes = array(Constants::TABLEAU_STRUCTURE_DETAILLE, Constants::TABLEAU_STRUCTURE_COMPTEURS, Constants::TABLEAU_STRUCTURE_GRAPH);
$this->view->operands = array('+', '-', '*', '/');
$this->view->pageTypes = array(
Constants::PAGE_GARDE,
Constants::PAGE_CONTENU,
Constants::PAGE_TABLEAUX,
);
$this->view->HautEtBasTypes = array(
Constants::HEADER => Constants::HEADER,
Constants::FOOTER => Constants::FOOTER,
);
$this->loadCss('styles/forms.css', 'form_css');
$this->view->config = Zend_Registry::get('AppConfig');
$ajaxContext = $this->_helper->getHelper('AjaxContext');
$ajaxContext->addActionContext('add-metier', 'json')
->setAutoJsonSerialization(true)
->initContext();
$this->_loggedInUser = Zend_Auth::getInstance()->getIdentity();
ini_set('display_errors', 1);
error_reporting(E_ALL);
}
Classname :
class MetierController extends Reporting_Controller {...}
After debugging, it goes to $this->_redirect('/metier/index') and then kick me out
What could be the problem ?