Google app engine imap invalid credentials - google-app-engine

I'm trying to get the emails of my users. I have a service account setup and an access token from the client library. I enter these details in to the xoauth library found here https://developers.google.com/gmail/xoauth2_libraries. But I keep getting invalid credentials errors. One account works and its the admin/impersonated account but no others work. This is a php app can someone please help.
$client = new Google_Client();
$client -> setApplicationName("TTS Dashboard");
$client -> setClientId(CLIENTID);
$client -> setClientSecret(CLIENTSECRET);
$oauth2 = new Google_Service_Oauth2($client);
$directoryService = new Google_Service_Directory($client);
$driveService = new Google_Service_Drive($client);
$calendarService = new Google_Service_Calendar($client);
if (isset($_SESSION['service_token'])) {
$client -> setAccessToken($_SESSION['service_token']);
}
$path = 'http://' . $_SERVER['HTTP_HOST'] . "/static/" . KEYFILEPATH;
$key = file_get_contents($path);
$cred = new Google_Auth_AssertionCredentials(SERVICEACCOUNTEMAIL, $scopes, $key);
$cred -> sub = $impersonatedEmailAddress;
$client -> setAssertionCredentials($cred);
$client -> getAuth() -> refreshTokenWithAssertion($cred);
if ($client -> getAuth() -> isAccessTokenExpired()) {
$client -> getAuth() -> refreshTokenWithAssertion($cred);
}
$_SESSION['service_token'] = $client -> getAccessToken();
function GetAccessTokenString() {
$accessToken = $_SESSION['service_token'];
$token = json_decode($accessToken, true);
$tokenString = $token['access_token'];
return $tokenString;
}
// Get access token string value
$tokenString = GetAccessTokenString();
tryImapLogin($studentEmail, $tokenString);

With service accounts and domain-wide delegation, you need to create one access token for each user, that is you need to impersonate each user, one after the other.
The admin access token will not give you access to other user's mailboxes.

Related

Power BI API with SPN Application rights

I have SPN that has Power BI - Tenant.ReadWrite.All Application permissions granted in AAD, but when making a call to list all groups from tenant, I get 401 Unauthorized.
string clientId = "{clientId}";
string clientSecret = "{clientSecred}";
string authority = "https://login.microsoftonline.com/{tenantId}";
string resource = "https://analysis.windows.net/powerbi/api";
string ApiUrl = "https://api.powerbi.com";
string[] scopes = new string[] { $"{resource}/.default" };
IConfidentialClientApplication app = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithClientSecret(clientSecret)
.WithAuthority(new Uri(authority))
.Build();
AuthenticationResult result = null;
result = app.AcquireTokenForClient(scopes).ExecuteAsync().Result;
var tokenCredentials = new TokenCredentials(result.AccessToken, "Bearer");
using (PowerBIClient _powerBIClient = new PowerBIClient(new Uri(ApiUrl), tokenCredentials))
{
var workspaceNames = _powerBIClient.Groups.GetGroupsAsAdmin(100, filter: "type eq 'Workspace'").Value.Select(x => x.Name);
};
Any clue what can be wrong? Bearer token returned seems to be all good.

Change user password for using Azure Graph API

I am not able to change the password of the logged in Azure AD B2C user.
I have Azure B2C tenant which is used for dev and QA.Also, i have two applications something-Local and something-QA used for DEV and QA respectively in Azure B2C as shown below and I have verified the settings of both the apps they are same
Below are the configurations of the applications
Here is my code which is used for B2C connection
private OpenIdConnectAuthenticationOptions CreateOptionsFromPolicy(string policy)
{
return new OpenIdConnectAuthenticationOptions
{
// For each policy, give OWIN the policy-specific metadata address, and
// set the authentication type to the id of the policy
// meta data
MetadataAddress = "https://login.microsoftonline.com/" + "mytenant" + "/v2.0/.well-known/openid-configuration?p=" + policy,
AuthenticationType = policy,
// These are standard OpenID Connect parameters, with values pulled from web.config
ClientId = AzureAdConfig.ClientId,
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthorizationCodeReceived = OnAuthorizationCodeReceived,
AuthenticationFailed = OnAuthenticationFailed,
SecurityTokenValidated = OnSecurityTokenValidated,
RedirectToIdentityProvider = OnRedirectToIdentityProvider,
},
Scope = "openid",
ResponseType = "id_token",
// This piece is optional - it is used for displaying the user's name in the navigation bar.
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
}
};
}
in the above code the ClientID used for QA and Dev are different.
Below is the code used to change the user password using graph API.
public async Task<HttpResponseMessage> ChangePassword(string currentPassword, string newPassword)
{
string userId = ClaimValues.ObjectIdentifier();
var adUser = _activeDirectoryClient.Users
.Where(u => u.ObjectId.Equals(userId))
.ExecuteAsync().Result.CurrentPage.FirstOrDefault();
string upn = adUser.UserPrincipalName;
var client = new HttpClient();
string uriString = "https://login.microsoftonline.com/"+ AzureAdConfig.Tenant + "/oauth2/token";
Uri requestUri = new Uri(uriString);
string requestString = "resource=https%3a%2f%2fgraph.windows.net&client_id=" + AzureAdConfig.AppId + "&grant_type=password&username=" + upn + "&password=" + currentPassword + "&client_secret=" + AzureAdConfig.AppKey;
var tokenResult = await client.PostAsync(requestUri, new StringContent(requestString, Encoding.UTF8, "application/x-www-form-urlencoded"));
if (tokenResult.IsSuccessStatusCode)
{
var stringResult = await tokenResult.Content.ReadAsStringAsync();
GraphApiTokenResult objectResult = JsonConvert.DeserializeObject<GraphApiTokenResult>(stringResult);
client = new HttpClient();
string requestUrl = AzureAdConfig.GraphResourceId + AzureAdConfig.Tenant + "/me/changePassword?" + AzureAdConfig.GraphVersion;
Uri graphUri = new Uri(requestUrl);
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", objectResult.access_token);
requestString = JsonConvert.SerializeObject(new
{
currentPassword = currentPassword,
newPassword = newPassword
});
var response = await client.PostAsync(graphUri, new StringContent(requestString, Encoding.UTF8, "application/json"));
return response;
}
else
{
return tokenResult;
}
}
Also, i wanted to understand what is the difference between Application Registrations in Azure Active directory service of azure and the Application in Azure AD B2C of azure?
Thanks in advance
To change user password by using Azure AD Graph API, first you should be a global administrator in your tenant, and then you could use PATCH https://graph.windows.net/myorganization/users/{user_id}?api-version and then update.
{
"passwordProfile": {
"password": "value",
"forceChangePasswordNextLogin": false
}
}
Also, i wanted to understand what is the difference between
Application Registrations in Azure Active directory service of azure
and the Application in Azure AD B2C of azure?
You can know about this from the difference between Azure AD tenant and Azure AD B2C tenant from here.
Hope it can help you.

Single Signon with Magento account from drupal

I have custom Magento script file as below which does login by just passing email and password to that PHP file.
It works fine when i'm making a call from browser.
But, I want to make this call through Drupal Module which i have created.
As i expected call is happening from Drupal module and i'm getting success message too. But login is not happening.
My hunch is that magento have some login restrictions which happening outside magento root folder.
Please find the source below.
Drupal directory - /www/drupal/
Magento directory - /www/drupal/store/
/www/drupal/store/api_config.php
<?php
error_reporting(E_ALL);
ini_set('display_errors', 'On');
require_once (dirname(dirname(realpath(__FILE__))).'/store/app/Mage.php');
umask(0);
Mage::app();
Mage::getSingleton('core/session', array('name' => 'frontend'));
$websiteId = Mage::app()->getWebsite()->getId();
$store = Mage::app()->getStore();
$response = array();
/www/drupal/store/api_login.php
<?php
require_once "api_config.php";
$session = Mage::getSingleton('customer/session');
//$session->start();
if (isset($_GET['email']) && !empty($_GET['email']) && isset($_GET['password']) && !empty($_GET['password'] )) {
if (!filter_var($_GET['email'], FILTER_VALIDATE_EMAIL) === false) {
$email = $_GET['email'];
$password = $_GET['password'];
try {
if ($session->login($email, $password )) {
$response['status'] = 'success';
$response['data'] = array($_GET);
$response['message'] = array('User loggedin Successfully.');
} else {
$response['status'] = 'error';
$response['data'] = array($_GET);
$response['message'] = array('User login failed.');
}
if ($session->getCustomer()->getIsJustConfirmed()) {
$this->_welcomeCustomer($session->getCustomer(), true);
}
} catch (Mage_Core_Exception $e) {
switch ($e->getCode()) {
case Mage_Customer_Model_Customer::EXCEPTION_EMAIL_NOT_CONFIRMED:
$value = Mage::helper('customer')->getEmailConfirmationUrl($email);
$message = Mage::helper('customer')->__('This account is not confirmed. Click here to resend confirmation email.', $value);
break;
case Mage_Customer_Model_Customer::EXCEPTION_INVALID_EMAIL_OR_PASSWORD:
$message = $e->getMessage();
break;
default:
$message = $e->getMessage();
}
//$session->addError($message);
$response['status'] = 'error';
$response['data'] = array($_GET);
$response['message'] = array($message);
echo $message;
$session->setUsername($email);
} catch (Exception $e) {
$response['status'] = 'error';
$response['data'] = array($_GET);
$response['message'] = array($e);
// Mage::logException($e); // PA DSS violation: this exception log can disclose customer password
}
} else {
//$session->addError('Login and password are required.');
$response['status'] = 'error';
$response['data'] = array($_GET);
$response['message'] = array('Invalid Email address');
}
} else {
//$session->addError('Login and password are required.');
$response['status'] = 'error';
$response['data'] = array($_GET);
$response['message'] = array('Login and password are required.');
}
print_r(json_encode($response, JSON_FORCE_OBJECT));die;
?>
/www/drupal/sites/all/modules/single_signon/single_signon.module
<?php
function single_signon_user_login(&$edit, $account) {
//store variable values
$postData = array();
$postData['email'] = $account->mail;
$postData['password'] = $edit['input']['pass'];
$inc = 1; //count of registration
if (!empty($postData['email']) && !empty($postData['password'])) {
// use of drupal_http_request
$data = http_build_query($postData, '', '&');
//$url = url('http://127.0.0.1/drupal/store/api_login.php?'.$data);
//$headers = array('Content-Type' => 'application/x-www-form-urlencoded');
//print_r($url);
// the actual sending of the data
$JSONresponse = drupal_http_request('http://127.0.0.1/drupal/store/api_login.php?email=john#example.com&password=password');
//print_r($JSONresponse);die;
$response = json_decode($JSONresponse->data, true);
if ($response['status']=='success') {
$inc+=1;
$message = 'Logged in successfully('.$inc.')';
drupal_set_message($message, $type = 'status', $repeat = FALSE); //message goes here
} else {
$message = 'Logged in failed. Due to '.$response['message'].'('.$inc.')';
drupal_set_message($message, $type = 'error ', $repeat = FALSE);
}
} else {
$message = 'Not able to log inside store('.$inc.')';
drupal_set_message($message, $type = 'status', $repeat = FALSE); //message goes here
}
}
?>
Any suggestions for findings to solve this mystery would be really helpful.
I'm not sure to understand it well : You have a php script using data send in the URL (GET) to connect a user in a session. And you would like the Drupal server to use it to connect directly to your Magento.
I think your code is working, but unfortunately it could not help the user to connect to Magento.
As this is the Drupal server asking for the connection, it would be the Drupal server session that will be connected and not the navigation user one.
If the user have to be connected, in his navigator, to the Magento server, it has to be the navigator witch must call the Magento script directly.
It could be done in an iframe or via Ajax I think.
I think you can also find some other solutions, as OAuth, but it will need a lot more of coding.
EDIT
I found some interesting subject about your problem :
Getting logged in user ID from Magento in external script - multiple session issue?
Magento Session from external page (same domain)
Magento external login will not create session cookie
I think you have to manually create the Magento session cookie on the user navigator, from the Drupal script.
You'll need to send back to Drupal the SessionID from Magento, using this method (I think, you'll have to verify) :
$response['sessionId'] = $session->getEncryptedSessionId();
And inside the Drupal script, you'll have to record a new cookie with the Magento session information. Maybe you have to have a look at a working Magento cookie to see how it is defined and what is its name.
if ($response['status']=='success') {
...
setcookie('frontend', $response['sessionId'], time() + 3600 * 24 * 180, '/');
...
}
You'll probably have to declare, in the settings of Magento, the path for cookies at '/'.
Can you give an example of the structure of the session cookie from Magento ?

CakePHP 2.4 Forgotten Password

I have just started using CakePHP and love using it! I have created a login system and registration system, however am really struggling with the "forgotten password" section.
I want to use a tokenhash and expiry date in the Users DB so that it cant be abused, users would need to enter username and email to get an activation link emailed to them with a newly generated tokenhash
There are quite a few tutorials out there but I find most of them work for the first part e.g. emailing the activation link/ resetting token and timer but all seem to fail on the change of the password.
Please help me, either with a working tutorial from the net or a solution that applies the above required things.
Thanks in advance
Steve
Below I am writing the code that I wrote for one of my project, this might help you out.
1- I created a new table which contains the unique token for every user.
Table Name:- user_password_resets
Columns : userclient_id, token
2- A email template name as:- change_password.html inside /webroot/template/change_password.html
public function login_send() {
$this->isLoggedIn(); //Check if the user is logged in
if($this->request->is('post')) { #if the form is submitted
$login = $this->data['User']['login'];
$conditions = array('User.login'=>$login);
if($this->User->hasAny($conditions)) {
$users = $this->User->find('first', array('conditions'=>$conditions));
#Generate the token
$token = md5(uniqid(rand(),true));
#Save token and other details in user_password_reset_links table
$users = $this->User->find('first', array('conditions'=>array('User.login'=>$login)));
$my_name = $users['User']['first_name'];
$reset_links = array();
$reset_links['UserPasswordReset']['userclient_id'] = $users['User']['client_id'];
$reset_links['UserPasswordReset']['token'] = $token;
$conditions = array('UserPasswordReset.userclient_id'=>$users['User']['client_id']);
if($this->UserPasswordReset->hasAny($conditions)) {
$user_id = $users['User']['client_id'];
$this->UserPasswordReset->updateAll(array('UserPasswordReset.token'=>"'$token'"), array("UserPasswordReset.userclient_id"=>"$user_id"));
} else {
$this->UserPasswordReset->create();
$this->UserPasswordReset->save($reset_links);
}
$password_reset_link = BASE_URL."users/reset_password/$token";
#Send Welcome Email
$mailContent = file_get_contents(BASE_URL . "templates/change_password.html");
$rootlink = BASE_URL;
$arrMail = array(
"{NICK}" => ucfirst($my_name),
"{rootlink}" => BASE_URL,
"{SITE_TITLE}" => SITE_TITLE,
"{PASSWORD_RESET_LINK}"=>$password_reset_link
);
$mails = explode(',', $users['User']['email']);
$msg = #str_replace(array_keys($arrMail), array_values($arrMail), $mailContent);
$data = array();
$data['to'] = #$mails[0];
$data['body'] = $msg;
$data['subject'] = SITE_TITLE.'- Reset Password.';
$this->send_mail($data);
$this->Session->setFlash('A password reset link has been sent to the email address.', 'default', array('class'=>'successMsg'));
$this->redirect(array('controller'=>'users', 'action'=>'login'));
exit;
} else {
$this->Session->setFlash('The Username entered is not registered with Captain Marketing.', 'default', array('class'=>'errorMsg'));
$this->redirect(array('controller'=>'users', 'action'=>'login_send'));
exit;
}
}
$this->set('title_for_layout', '-Send password reset link');
}

Google API - using the Service Directory

I have an APP in the Google API console. It has the Admin SDK enabled, and also the Marketplace SDK. I have registered it as a service account, and I have the key file, etc. When I try to get users from a certain domain, It always shows me one message - "Error calling GET https://www.googleapis.com/admin/directory/v1/users?domain=mydomain.com: (403) Not Authorized to access this resource/api". The code I have is this:
$client = new Google_Client();
$client->setApplicationName("Client_User_Feed");
$key = file_get_contents('/path/to/key/key-file-privatekey.p12');
$cred = new Google_Auth_AssertionCredentials(
'{code}#developer.gserviceaccount.com',
array('https://www.googleapis.com/auth/admin.directory.user'),
$key
);
$client->setAssertionCredentials($cred);
$service = new Google_Service_Directory($client);
$users = $service->users->listUsers(array('domain' => 'mydomain.com'));
How can I solve this issue?
You need to impersonate an admin user with something like:
$adminUser = 'admin#domain.com';
$cred->sub = $adminUser;
Example code fetching userID:
$client_id = '{code}.apps.googleusercontent.com'; //Client ID from Developers Console
$service_account_name = '{code}#developer.gserviceaccount.com'; //Email Address from Developers Console
$key_file_location = '{path}{file}.p12'; //Path to the P12 key downloaded from Developers Console
$impersonateUser = 'standarduser#domain.com'; //The user's account we are fetching information from
try {
$client = new Google_Client(); //Instantiate the Google Client
$client->setApplicationName("ApplicationName");
$adminService = new Google_Service_Directory($client);
$key = file_get_contents($key_file_location);
$cred = new Google_Auth_AssertionCredentials( //Instantiate the Auth class
$service_account_name,
array('https://www.googleapis.com/auth/admin.directory.user'), //Set the scope
$key
);
$adminUser = 'admin#domain.com';
$cred->sub = $adminUser; //The sub function of Auth lets us impersonate a user so that our service account ($client_id) can act on the user's behalf
$client->setAssertionCredentials($cred);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($cred);
}
$getUser = getUserId($adminService, $impersonateUser);
$impersonateUser = $getUser['primaryEmail'];
if (isset($impersonateUser) && !empty($impersonateUser)) {
$_SESSION['gmailUserID'] = $impersonateUser;
}
//echo $_SESSION['gmailUserID'] . "<br />";
} catch (Exception $e) {
LogErr($e);
}
function getUserId($adminService, $impersonateUser) {
try {
$userId = $adminService->users->get($impersonateUser);
return $userId;
} catch (Exception $e) {
LogErr($e);
}
}

Resources